我试图让解析器采用一系列冒号分隔的单词并将它们转换为数组。
这是SSCCE。
import util.parsing.combinator._
class Element {
def getSuper() = "TODO"
}
class Comp extends RegexParsers with PackratParsers {
lazy val element: PackratParser[Element] = (
"foo") ^^ {
s => new Element
}
lazy val list: PackratParser[Array[Element]] = (
(element ~ ";" ~ list) |
element ~ ";") ^^
{
case a ~ ";" ~ b => Array(a) ++ b
case a ~ ";" => Array(a)
}
}
object Compiler extends Comp {
def main(args: Array[String]) = {
println(parseAll(list, "foo; foo; foo;"))
}
}
它没有工作,而且它没有编译,如果不是我不会问它。这是我收到的错误消息。有没有办法从Serializable转换为GenTraversableOnce?
~/Documents/Git/Workspace/Uncool/Scales$ scalac stov.scala
stov.scala:19: error: type mismatch;
found : java.io.Serializable
required: scala.collection.GenTraversableOnce[?]
case a ~ ";" ~ b => Array(a) ++ b
^
one error found
答案 0 :(得分:3)
我怀疑是|
组合子。
(element ~ ";" ~ list)
的类型为~[~[Element, String], Array[Element]]
,element ~ ";"
的类型为~[Element, String]
。
因此,当在这些解析器上应用|
组合子时,它返回Parser[U]
,其中U
是T
([U >: T]
)的超类型。
此处T
的类型为~[~[Element, String], Array[Element]]
,U
的类型为~[Element, String]
。
因此Array[Element]
和String
之间最具体的类型是Serializable
。
在~[Element, String]
和Element
之间Object
。这就是为什么|
的类型为~[Serializable, Object]
。
因此,在应用map操作时,您需要提供一个函数~[Serializable, Object] => U
,其中U
为Array[Element]
,因为函数的返回类型为PackratParser[Array[Element]]
。
现在唯一可能的匹配是:
case obj ~ ser => //do what you want
现在您看到您在地图中尝试匹配的模式根本就是错误的。即使你返回一个空数组(只是为了编译它),你也会发现它在运行时会导致匹配错误。
那就是说,我建议首先分别映射每个组合器:
lazy val list: PackratParser[Array[Element]] =
(element ~ ";" ~ list) ^^ {case a ~ ";" ~ b => Array(a) ++ b} |
(element ~ ";") ^^ {case a ~ ";" => Array(a)}
但您正在寻找的模式已经使用rep
组合器实现(您还可以查看repsep
,但是您需要处理上一个;
分开):
lazy val list: PackratParser[Array[Element]] = rep(element <~ ";") ^^ (_.toArray)