0

したがって、Scala パーサーを使用する場合は次のようになります。

case class MyParser(foos: List[String]) extends Parsers {
  val bars: List[Parser[String]] = foos.map(parserFromString)

  // Expensive function
  def parserFromString(s: String): Parser[String] = ???
}

Parserはパス依存型であるため、このコードをリファクタリングbarsしてコンストラクターから渡すことはできません。parserFromString私の使用例では、実際に構造が O(N!) になるMyParserような方法で を作成することに注意してください。MyParserN = foos.size

だから今、bars別の経由でに追加したいとしfooます。FPの方法はbars、コンストラクターに含めるようにリファクタリングしてから、のようなものを定義することですdef +(foo: String): MyParser = copy(bars = bars :+ parserFromString(foo)が、前述のように、最初から再作成する必要はありません。

私の解決策は、barsaを作成しprivate var、それをUnitmethodupdateで変更することです。つまり、def update(foo: String): Unit = bars +:= parserFromString(foo)

私の最初の質問は非常に単純です。ミューテーションを使用する必要がありますか?

2 番目の質問: Parboiled2 はこれに悩まされていますか? それらはパス依存型を使用していますか (一見そうは見えません)、そうであれば、なぜ Scala パーサーはパス依存型を使用するのでしょうか?

parboiled2 がパス依存型に悩まされていない場合、これだけでも使用する理由になります!

なぜパラメーターから s を作成する必要があるのか​​ 疑問に思っている人がいれば、Parserそれは、ユーザーがマクロを定義し、それらのマクロを他のマクロの定義に使用できる言語を実装しているためです。いいえ、誰かが私にデザインを変更するように言う前に、私はできません。また、後でマルチスレッドが必要になるため、可変性は本当に望んでいません。

4

1 に答える 1

1

Parserはパス依存型であるため、コンストラクターからバーを渡すことができるようにこのコードをリファクタリングすることはできません。

はい、次のことができます。

// could also be trait and mixed in where you need it
object MyParsers extends Parsers {
  case class MyParser(bars: List[Parser[String]]) {
    def +(foo: String): MyParser = copy(bars = bars :+ parserFromString(foo))
    ...
  }
}

Parboiled2 はこれに苦しんでいますか? パス依存型を使っているか(一見そう見えない)

いいえ、例からわかるように。

もしそうなら、なぜScalaパーサーはパス依存型を使用するのですか

上に示したように、これは問題にはなりません。状況によっては、パス依存型で問題が発生しましたが、パーサーを使用していません

Scala パーサーと parboiled のどちらを選択するかについては、個人的には、パフォーマンス、どちらの DSL を好むかなどについてもっと考えたいと思います。前回 parboiled を見たとき、エラー報告に実際に影響を与える方法はありませんでしたが、これは現在修正されています .

于 2015-03-29T08:55:11.010 に答える