这是一个序列化操作,而Scalaz提供了一种快捷方式(通常情况下,你不需要使用Scalaz的显式实例定义模板,但这是一个特殊情况):
import scala.util.parsing.combinator.RegexParsers
import scalaz._, Scalaz._
object MyParser extends RegexParsers {
implicit val pm = std.util.parsing.combinator.parser.parserMonad(this)
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combine[T](parsers: List[Parser[T]]): Parser[List[T]] = parsers.sequenceU
def combinedDirective: Parser[List[String]] =
combine(List(aDirective, bDirective))
}
接下来:
scala> MyParser.parseAll(MyParser.combinedDirective, "ab")
res0: MyParser.ParseResult[List[String]] = [1.3] parsed: List(a, b)
你可以使用fold自定义它:
import scala.util.parsing.combinator.RegexParsers
object MyParser extends RegexParsers {
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combine[T](parsers: List[Parser[T]]): Parser[List[T]] =
parsers.foldRight(success(List.empty[T])) {
case (p, acc) => for {
pRes <- p
accRes <- acc
} yield pRes :: accRes
}
def combinedDirective: Parser[List[String]] =
combine(List(aDirective, bDirective))
}
它的功能完全相同。诀窍就是正确地设置基础,它需要是一个解析器,总是以空列表作为其值成功。
更新:如果您正在定义一个类而不是对象,则上述Scalaz方法将无法正常工作(由于许多奇怪的原因——简而言之,this
不够稳定)。不过,您可以轻松地定义自己的monad实例:
class MyParser extends RegexParsers {
implicit val pm = new Monad[Parser] {
def point[A](a: => A): Parser[A] = success(a)
def bind[A, B](fa: Parser[A])(f: A => Parser[B]): Parser[B] = fa flatMap f
}
def aDirective: Parser[String] = "a" ^^ { case _ => "a" }
def bDirective: Parser[String] = "b" ^^ { case _ => "b" }
def combine[T](parsers: List[Parser[T]]): Parser[List[T]] = parsers.sequenceU
def combinedDirective: Parser[List[String]] =
combine(List(aDirective, bDirective))
}
在这里使用sequence
,你实际上不需要一个单子实例,只需要一个应用函子即可,但是定义实际上更加方便,并且单子实例可能在其他情况下很有用。
class
而不是object
,但我不确定这是否有影响?我看到的编译错误是: - adamretterTestParser.this.Parser [T]
解构为由类型类scalaz.Applicative
分类的M [_]
类型构造函数。 编译“implicitly [scalaz.Applicative [type constructor]]”以检查类型类是否定义,并查看对象Unapply中的隐式内容,它仅涵盖常见类型“形状”。 def combine [T](parsers:List [Parser [T]]):Parser [List [T]] = parsers.sequenceU - adamretter