Scala中的应用解析器示例

时间:2015-06-06 17:55:33

标签: scala parsing scalaz applicative

这是我以前的question

的新版本

我们可以将解析器定义为type Parser[A] = String => List[(A, String)]。解析器接受一个输入字符串并产生一系列对。每对包含解析结果和输入的未消耗部分。 (详见article

现在我们可以定义一个解析器pa,如果第一个输入字符为a则成功,否则失败。

def symbol(c: Char): Parser[Char] = {s: String => 
  s.toList match { case x :: xs if x == c => List((x, xs.mkString)); case _ => Nil } 
}

val pa = symbol('a')

我们还可以为map定义flatMapParser[A],然后使用它们来构建解析器:

val pa = symbol('a')
val pb = symbol('b')
val pab: Parser[(Char, Char)] = for (a <- pa; b <- pa) yield (a, b)

turned out虽然我们可以使用<*>组合解析器。

  

应用解析器的示例。假设我们想要识别嵌套括号并计算最大嵌套深度。语法S - > (S)S | epsilon描述了这种结构,它直接反映在解析器中。

pS = (max . (+1)) <$ pSym '(' <*> pS <* pSym ')' <|> pure 0

不幸的是,我无法理解这个例子。所以我的问题是:

  • 如何为解析器定义<*>? (不是flatMap)?
  • 如何将此示例翻译为Scala(使用scalaz)?

1 个答案:

答案 0 :(得分:1)

<*>(可怕的名字)显然有这个签名:

<*>[B](f: F[(A) ⇒ B]): F[B]

因此,让我们只是追逐类型,考虑解析器应该做什么 - 得益于List已经实现flatMap的事实:

def <*>[A, B](fa: Parser[A], fab: Parser[(A) => B]) =
  new Parser[B] {
    def apply(s: String) =
      for {
        (a, rem1) ← fa(s)
        (ab, rem2) ← fab(rem1)
      } yield (ab(a), rem2)
  }

这看似合理的实现 - 先解析a,然后从剩余部分解析ab,然后我们得到结果。

这个例子对我来说太具有象征意义了,我不知道Haskell - 如果你能找到<$<|>的文档,那么我就试试吧。< / p>