【问题标题】:How do I pass ParseResults to other methods?如何将 ParseResults 传递给其他方法?
【发布时间】:2012-08-16 15:07:29
【问题描述】:
void whatever() {
  // ...
  val parser = new MyParser
  val parse = parser.parse(input)
  if (parse successful) {
    semanticAnalysis(parse)
  }
}

void semanticAnalysis(parse: DontKnowTheCorrectType) {
  // ...
}

我必须为形参parse 赋予什么类型?将鼠标悬停在whatever 内的parse 上会显示val parse: parser.ParseResult[parsing.Program],但当然这不能作为semanticAnalysis 的参数类型,因为局部变量parse 不在该范围内。

【问题讨论】:

    标签: scala types parameters parser-combinators


    【解决方案1】:

    解析结果是依赖于路径的类型,因为它们是此特定解析器的结果,并且不能保证它们是兼容的。

    这就是为什么解析器通常不会以您使用它们的方式 (new MyParser) 而是以 object 的方式实例化。

    object MyParser extends RegexParsers { 
       def statements : Parser[List[Statement]] = // ...
    } 
    
    def handleResult(res: MyParser.ParseResult[List[Statement]]) = { // ... } 
    
    val res = MyParser.parseAll(MyParser.statements, "/* */")
    

    如果您需要更多动态行为(或想要并发解析,parser combinators aren't thread-safe,哎哟),您只需保持解析器对象可访问(且稳定),无论您想在何处使用其结果。

    可悲的是,将解析器及其结果一起传递并不是一件容易的事,因为您会遇到依赖方法类型的禁令,例如

      def fun(p: scala.util.parsing.combinator.Parsers, res: p.ParseResult[_]) = {}
    

    不会编译(“非法依赖方法类型”),但如果必须的话,有一些方法可以解决这个问题,比如this question 的答案。

    【讨论】:

    • 这会是个问题,因为我在解析器中添加了一些状态...我知道,这不是纯粹的功能性,我可能会为此在地狱中燃烧:)
    • 不能def fun(p: scala.util.parsing.combinator.Parsers)(res: p.ParseResult[_]) = {}吗?
    【解决方案2】:

    您应该能够将semanticAnalysis 定义为:

    def semanticAnalysis(parse: MyParser#ParseResult[parsing.Program]) = {
      ...
    }
    

    注意使用# 而不是. 作为类型。还有更多细节about type projections here,但基本上,parser.ParseResult 对于每个parser 是不同的,而MyParser#ParseResult 对于所有parser 实例都是相同的。

    但是,正如themel 所说,您可能应该使用object 而不是class

    【讨论】:

      【解决方案3】:

      你可以这样改写:

      def whatever() {
        // ...
        val parser = new MyParser
        def semanticAnalysis(parse: parser.ParseResult) {
          // ...
        }
        val parse = parser.parse(input)
        if (parse successful) {
          semanticAnalysis(parse)
        }
      }
      

      如果您从多个地方调用它,那么可能是这样的:

        class SemanticAnalysis(parser: Parser) {
          def apply(parse: parser.ParseResult) {
            // ...
          }
        }
      

      然后

        if (parse successful) {
          new SemanticAnalysis(parser)(parse)
        }
      

      【讨论】:

        【解决方案4】:

        当我需要在程序的其他部分使用解析器组合器的结果时,我从依赖路径的ParseResult中提取成功结果或错误消息,并将数据放入一个独立的类型中。它比我喜欢的更冗长,但我想将组合器实例保留为解析器的实现细节。

        sealed abstract class Result[+T]
        case class Success[T](result: T) extends Result[T]
        case class Failure(msg: String) extends Result[Nothing]
        case class Error(msg: String) extends Result[Nothing]
        
        /** Parse the package declarations in the file. */
        def parse(file: String): Result[List[Package]] = {
          val stream = ... // open the file...
          val parser = new MyParser
          val result = parser.parseAll(parser.packages, stream)   
          stream.close()
          result match {
            case parser.Success(packages, _) => Success(packages)
            case parser.Failure(msg, _) => Failure(msg)
            case parser.Error(msg, _) => Error(msg)
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2020-05-18
          • 1970-01-01
          • 2016-08-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-01
          • 1970-01-01
          相关资源
          最近更新 更多