1
void whatever() {
  // ...
  val parser = new MyParser
  val parse = parser.parse(input)
  if (parse successful) {
    semanticAnalysis(parse)
  }
}

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

仮パラメータにはどの型を指定する必要がありますparseか? parse内部にカーソルを合わせると と表示されますが、ローカル変数がスコープ内にないため、もちろんそれは のパラメータ タイプとしては機能しませんwhateverval parse: parser.ParseResult[parsing.Program]semanticAnalysisparse

4

4 に答える 4

3

解析結果は、この特定のパーサーの結果であり、互換性が保証されていないため、パスに依存するタイプです。

これが、パーサーが通常、使用方法(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, "/* */")

より動的な動作が必要な場合(または同時解析が必要な場合、パーサーコンビネーターはスレッドセーフではありません)、結果を使用する場所でパーサーオブジェクトにアクセスできる(そして安定している)必要があります。

悲しいことに、パーサーとその結果を一緒に渡すことは、依存するメソッドタイプの禁止に遭遇するため、簡単ではありません。

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

コンパイルされません(「違法な依存メソッドタイプ」)が、この質問への回答のように、必要に応じてそれを回避する方法があります。

于 2012-08-21T09:41:06.460 に答える
1

次のように定義できるはずですsemanticAnalysis

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

#型の代わりにfor を使用していることに注意してください.型プロジェクションについてはこちらに詳細がありますが、基本的にparser.ParseResultは ごとparserに異なり、MyParser#ParseResultはすべてのparserインスタンスで同じです。

しかし、themelが言うように、おそらくobject代わりにを使用する必要がありclassます。

于 2012-08-21T10:30:04.590 に答える
0

次のように書き換えることができます。

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)
  }
于 2012-08-21T20:51:59.697 に答える
0

プログラムの他の部分でパーサー コンビネーターの結果を使用する必要がある場合、パス依存から成功の結果またはエラー メッセージを抽出し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)
  }
}
于 2013-09-14T23:31:47.497 に答える