What you re describing (and what you ve more or less reinvented in your implementation with foldLeft
and ~
) is essentially Haskell s sequence
for monads (really you only need an applicative functor, but that s irrelevant here). sequence
takes a list of monadic values and returns a monadic list of values. Parser
is a monad, so sequence
for Parser
would change a List[Parser[A]]
into a Parser[List[A]]
.
Scalaz gives you sequence
, but off the top of my head I don t know if there s a nice way to get the necessary Applicative
instance for Parser
. Fortunately you can roll your own pretty easily (I m directly translating the Haskell definition):
import scala.util.parsing.combinator._
object parser extends RegexParsers {
val integer = """d+""".r
val counts = List(1, 2, 3)
val parsers = counts.map(repN(_, integer))
val line = parsers.foldRight(success(Nil: List[List[String]])) {
(m, n) => for { x <- m ; xs <- n } yield (x :: xs)
}
def apply(s: String) = parseAll(line, s)
}
这使我们想到List(List(1), List(2,3), List(4,5, 6)
,parser(”1 2 3 4 5 6”)
。
(说明:使用<代码>的Im 这里是一个方便的完整的例子,但这一办法一般运作。
如果我们取消<<<><>>><>条码/代码>,那么今后将会出现什么更为清楚。 理解:
val line = parsers.foldRight(success(Nil: List[List[String]])) {
(current, acc) => current.flatMap(x => acc.map(x :: _))
}
我们可以将<条码>flatMap作为<条码>、<条码>和<条码>作为<条码>。
val line = parsers.foldRight(success(Nil: List[List[String]])) {
(current, acc) => current into (x => acc ^^ (x :: _))
}
This isn t too far from your formulation, except that we re using a right fold instead of reversing and aren t building up and breaking down the ~
s.
提高效率: 我们的这两项执行工作都将造成无休止的警钟。 在我的经验中,这只是一个与Schala族长结合的生活事实。 To quote ,例如:
Scala s parser combinators aren t very efficient. They weren t
designed to be. They re good for doing small tasks with relatively
small inputs.
我的<代码>squence-y办法述及贵问题中的“可读”部分,而且几乎肯定是解决与S Scala族长结合者问题的最佳途径。 这比你的执行效率低一些,应该对几千个团体处以罚款。 如果你需要处理多于这种情况,就必须在<条码>scala.util.parsing.combinator之外检查。 我建议:
def parse(counts: Seq[Int], input: String): Option[Seq[Seq[Int]]] = {
val parsed = try {
Some(input.split(" ").map(_.toInt))
} catch {
case _ : java.lang.NumberFormatException => None
}
parsed.flatMap { ints =>
if (ints.length != counts.sum) None
else Some(counts.foldLeft((Seq.empty[Seq[Int]], ints)) {
case ((collected, remaining), count) => {
val (m, n) = remaining.splitAt(count)
(m.toSeq +: collected, n)
}
}._1.reverse)
}
}
没有任何保障,但在我的制度上,它向100k英寸的集团倾斜。