Scala中的类型安全的解析器组合器

时间:2014-04-02 08:46:40

标签: scala declarative parser-combinators postfix-notation

我受到启发,使用反向抛光表示法作为我将要教授的课程的解析器组合器的示例,但是,我的解决方案最终使用类型List[Any]分别存储浮点数和二元运算符。最后,我递归地解构列表并在遇到它时应用二元运算符。整个实现在这里:

import scala.util.parsing.combinator._

trait Ops {
  type Op = (Float,Float) => Float

  def add(x: Float, y: Float) = x + y
  def sub(x: Float, y: Float) = x - y
  def mul(x: Float, y: Float) = x * y
  def div(x: Float, y: Float) = x / y
}

trait PolishParser extends Ops with JavaTokenParsers {

  // Converts a floating point number as a String to Float
  def num: Parser[Float] = floatingPointNumber ^^ (_.toFloat)
  // Parses an operator and converts it to the underlying function it logically maps to
  def operator: Parser[Op] = ("*" | "/" | "+" | "-") ^^ {
    case "+" => add
    case "-" => sub
    case "*" => mul
    case "/" => div
  }

}

trait PolishSemantics extends PolishParser {

  def polish:Parser[Float] = rep(num | operator) ^^ ( xs => reduce(xs).head )

  def pop2(xs:List[Float],f:Op) = (xs take 2 reduce f) :: (xs drop 2)

  def reduce(input:List[Any],stack:List[Float] = Nil):List[Float] = input match {
    case (f:Op) :: xs => reduce(xs,pop2(stack,f))
    case (x:Float) :: xs => reduce(xs,x :: stack)
    case Nil => stack
    case _ => sys.error("Unexpected input")
  }

}

class PolishInterpreter extends PolishParser with PolishSemantics {
  // Parse an expression and return the calculated result as a String
  def interpret(expression: String) = parseAll(polish, expression)
}

object Calculator extends PolishSemantics {

  def main(args: Array[String]) {
    val pi = new PolishInterpreter
    println("input: " + args(0))
    println("result: " + pi.interpret(args(0)))
  }

}

我想要实现的是不在reduce函数中使用type-pattern。一种解决方案当然是按照以下意义制作自定义类型层次结构:

trait Elem
case class Floating(f:Float) extends Elem
case class Operator(o: (Float,Float) => Float) extends Elem

通过这种方式,我可以通过unapply方法在case-classes上使用模式匹配,但这也需要对代码进行大量重构。 另一种方法可能是在解析时直接应用语义,这将允许我只使用浮点数的“堆栈”,然后在解析它们之后立即处理运算符。这当然会完全破坏解析器 - 组合器工作的声明性方式,并且会成为对世界上所有好事的犯罪。

当然,我知道这是挑剔,但每个人都是一个试图离开的软件工程师,我准备好最后的建议,让这个例子变得完美。有任何想法吗? :)

0 个答案:

没有答案