したがって、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
ような方法で を作成することに注意してください。MyParser
N = foos.size
だから今、bars
別の経由でに追加したいとしfoo
ます。FPの方法はbars
、コンストラクターに含めるようにリファクタリングしてから、のようなものを定義することですdef +(foo: String): MyParser = copy(bars = bars :+ parserFromString(foo)
が、前述のように、最初から再作成する必要はありません。
私の解決策は、bars
aを作成しprivate var
、それをUnit
methodupdate
で変更することです。つまり、def update(foo: String): Unit = bars +:= parserFromString(foo)
私の最初の質問は非常に単純です。ミューテーションを使用する必要がありますか?
2 番目の質問: Parboiled2 はこれに悩まされていますか? それらはパス依存型を使用していますか (一見そうは見えません)、そうであれば、なぜ Scala パーサーはパス依存型を使用するのでしょうか?
parboiled2 がパス依存型に悩まされていない場合、これだけでも使用する理由になります!
なぜパラメーターから s を作成する必要があるのか 疑問に思っている人がいれば、Parser
それは、ユーザーがマクロを定義し、それらのマクロを他のマクロの定義に使用できる言語を実装しているためです。いいえ、誰かが私にデザインを変更するように言う前に、私はできません。また、後でマルチスレッドが必要になるため、可変性は本当に望んでいません。