这是我以前的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
定义flatMap
和Parser[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
)?scalaz
)? 答案 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>