Я новичок в Scala и сейчас изучаю комбинатор синтаксического анализатора Scala, пишу «MiniLogicParser», мини-анализатор для формул пропозициональной логики. Мне удалось частично разобрать его, но не могу преобразовать в класс case. Я пробовал несколько кодов, как показано ниже.

import java.io._
import scala.util.parsing.combinator._

sealed trait Bool[+A]
case object True extends Bool[Nothing]
case class Var[A](label: A) extends Bool[A]
case class Not[A](child: Bool[A]) extends Bool[A]
case class And[A](children: List[Bool[A]]) extends Bool[A]

object LogicParser extends RegexParsers {
  override def skipWhitespace = true

  def formula = ( TRUE | not | and | textdata )
  def TRUE  = "TRUE"
  def not : Parser[_] = NEG ~ formula  ^^ {case ( "!"  ~ formula) => Not(formula)}
  def and : Parser[_] = LPARENTHESIS ~ formula ~ opt(CONJUNCT ~ formula) ~ RPARENTHESIS
  def NEG = "!"
  def CONJUNCT = "&&"
  def LPARENTHESIS = '('
  def RPARENTHESIS = ')'
  def textdata = "[a-zA-Z0-9]+".r

  def apply(input: String): Either[String, Any] = parseAll(formula, input) match {
      case Success(logicData, next)        => Right(logicData)
      case NoSuccess(errorMessage, next) => Left(s"$errorMessage on line ${next.pos.line} on column ${next.pos.column}")
    }
}

Но компиляция не удалась со следующим сообщением об ошибке

[error] ... MiniLogicParser.scala:15 type mismatch;  
[error]  found : Any 
[error]  required: Bool[?]  
[error]  def not : Parser[_] = NEG ~ formula  ^^ {case ( "!"  ~ formula) => Not(formula)}

Я частично могу понять сообщение об ошибке; т.е. это означает, что для строки 15, где я пытался преобразовать результат синтаксического анализа в класс case, происходит несоответствие типов. Однако я не понимаю, как исправить эту ошибку.

1
tsutomu 5 Май 2016 в 11:35

2 ответа

Лучший ответ

Я немного адаптировал ваш парсер.

import scala.util.parsing.combinator._
sealed trait Bool[+A]
case object True extends Bool[Nothing]
case class Var[A](label: A) extends Bool[A]
case class Not[A](child: Bool[A]) extends Bool[A]
case class And[A](l: Bool[A], r: Bool[A]) extends Bool[A]


object LogicParser extends RegexParsers with App {
  override def skipWhitespace = true

  def NEG = "!"
  def CONJUNCT = "&&"
  def LP = '('
  def RP = ')'

  def TRUE = literal("TRUE") ^^ { case _ => True }
  def textdata = "[a-zA-Z0-9]+".r ^^ { case x => Var(x) }

  def formula: Parser[Bool[_]] = textdata | and | not | TRUE
  def not = NEG ~ formula ^^ { case n ~ f => Not(f) }
  def and = LP ~> formula ~ CONJUNCT ~ formula <~ RP ^^ { case f1 ~ c ~ f2 => And(f1, f2) }

  def apply(input: String): Either[String, Any] = parseAll(formula, input) match {
    case Success(logicData, next) => Right(logicData)
    case NoSuccess(errorMessage, next) => Left(s"$errorMessage on line ${next.pos.line} on column ${next.pos.column}")
  }

  println(apply("TRUE"))            // Right(Var(TRUE))
  println(apply("(A && B)"))        // Right(And(Var(A),Var(B)))
  println(apply("((A && B) && C)")) // Right(And(And(Var(A),Var(B)),Var(C)))
  println(apply("!(A && !B)"))      // Right(Not(And(Var(A),Not(Var(B)))))
}
1
vvg 5 Май 2016 в 10:24

Дочерний элемент узла Not имеет тип Bool. Однако в строке 15 formula, значение, которое вы хотите передать методу apply Not, имеет тип Any. Вы можете ограничить средство извлечения (т. Е. Оператор case -) только для соответствия значениям formula, которые относятся к типу Bool, добавив информацию о типе после двоеточия:

case ( "!"  ~ (formula: Bool[_]))

Следовательно, метод not будет выглядеть так:

def not : Parser[_] = NEG ~ formula  ^^ {case ( "!"  ~ (formula: Bool[_])) => Not(formula)}

Однако теперь, например, "!TRUE" больше не соответствует, потому что "TRUE" еще не относится к типу Bool. Это можно исправить, расширив ваш синтаксический анализатор для преобразования строки в Bool, например,

def TRUE  = "TRUE" ^^ (_ => True)
0
Kulu Limpa 5 Май 2016 в 10:06