Scala 中具有路径相关类型(解析器)的纯函数式编程?

Pure Functional Programming with Path Dependent Types (Parsers) in Scala?

因此,当使用 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 实际上创建了一个 MyParser,使得 MyParser 构造变为 O(N!),其中 N = foos.size.

所以假设现在我想通过另一个 foo 添加到 bars。 FP 方法是重构以在构造函数中包含 bars,然后定义类似 def +(foo: String): MyParser = copy(bars = bars :+ parserFromString(foo) 的内容,但如前所述,我不能从头开始重新创建。

我的解决方案是将 bars 设为 private var 并使用 Unit 方法 update 对其进行变异,即 def update(foo: String): Unit = bars +:= parserFromString(foo)

我的第一个问题很简单:我卡住了吗?我必须使用突变吗?

第二个问题:Parboiled2是否有此问题?它们是否使用路径依赖类型(乍一看不像),如果是,为什么 Scala 解析器使用路径依赖类型?

如果 parboiled2 不受路径依赖类型的影响,这本身就是使用它的理由!

如果有人想知道为什么我需要从参数创建 Parsers,那是因为我正在实现一种语言,用户可以在其中定义宏并在定义其他宏时使用这些宏。所以不,在任何人试图告诉我改变设计之前,我不能。我也真的不想要可变性,因为稍后我将需要多线程。

Parser is a path-dependent type, so this code cannot be refactored so that bars can be passed in from the constructor.

是的,它可以:

// 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))
    ...
  }
}

does Parboiled2 suffer from this? Do they use path-dependent types (at a glance it doesn't look like it)

没有,从examples.

可以看出

and if so why do Scala parsers use path-dependent types

如上所示,这应该不是问题。在某些情况下,我 运行 遇到了路径相关类型的麻烦,但没有使用解析器。

对于 Scala 解析器和 parboiled 之间的选择,我个人会更多地考虑性能,您更喜欢哪种 DSL 等。上次我查看 parboiled 时,它没有真正的方法来影响错误报告,但是这个is fixed now.