问题
This is a new version of my previous question
We can define a parser as type Parser[A] = String => List[(A, String)]
. The parser takes an input string and yields a sequence of pairs. Each pair consists of the parsing result and unconsumed part of the input. (See more in this article)
Now we can define a parser pa
, which succeeds if the 1st input character is a
and fails otherwise.
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')
We can also define map
and flatMap
for Parser[A]
and then use them to compose parsers:
val pa = symbol('a')
val pb = symbol('b')
val pab: Parser[(Char, Char)] = for (a <- pa; b <- pa) yield (a, b)
It is turned out though that we can compose parsers with <*>
too.
An example of an applicative parser. Suppose we want to recognise nested parentheses and compute the maximum nesting depth. The grammar S -> (S)S | epsilon describes this structure, which is directly reflected in the parser.
pS = (max . (+1)) <$ pSym '(' <*> pS <* pSym ')' <|> pure 0
Unfortunately I can't get my head around this example. So my questions are:
- How to define
<*>
for parsers ? (not withflatMap
) ? - How to translate this example to Scala (with
scalaz
) ?
回答1:
<*>
(terrible name) apparently has this signature:
<*>[B](f: F[(A) ⇒ B]): F[B]
So let's just chase the types through, thinking about what a parser should do - helped by the fact that List
already implements 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)
}
That looks like a sensible implementation - parse a
first, then parse ab
from the remainder, and then we have our result.
That example is too symbolic for me and I don't know Haskell - if you can find documentation for the <$
and <|>
then I'll give it a go.
来源:https://stackoverflow.com/questions/30685920/applicative-parser-example-in-scala