2

我不知道如何解决我的问题。我有一个作业,我需要使用教授制定的规则来简化表达式。我需要接受表达式字符串:

"(and(x x))"
"(or (and x z) y)"
"(and (or z (not x))(or e a))"

并使用规则简化它们:

(or x nil) => x; 
(or nil x) => x;
(or 1 x) => 1;
(or x 1) => 1;
(and x nil) => nil; 
(and nil x) => nil;
(and x 1) => x; 
(and 1 x) => x;
(not nil) => 1;
(not 1) => nil;
(not (and x y)) => (or (not x) (not y));
(not (or x y)) => (and (not x) (not y));

我决定采用上面的确切形式(不能是任何其他方式)的表达式,并将其解析为一个数组,因此例如在每个索引中,它看起来像这样:

and or x y z //ArrayBuffer[String]

然后我使用一个递归函数来检查左右表达式,直到它得到简化的表达式。我的问题不在于规则,因为我已经弄清楚了。我基本上完成了3个案例,它们是:

"(and z (or x y)" // the case when the left symbol is simple but the right side must be recursed
"(and (or x y) z)" // case when the right symbol is simple but the right side must be recursed
"(and x y)" // simple case where no recursion is necessary

我错过了必须递归左右符号才能获得那些简化符号的情况。我没有办法知道它们何时结束或开始,并且在很多情况下,即使在这些内部表达式中也必须递归:

"(and (or (and x y) z)(or x a))"
"(and (or (and x y) z)(or (and y z) a))"

我已经考虑过如何使用我拥有的当前实现以有效的方式完成此操作,但还没有得到任何东西。我正在征求一些关于如何去做的建议。我没有提供代码,因为我想自己完成它,只需要朝着正确的方向轻推。如果需要澄清,请询问,我会这样做。再次感谢提前!

4

3 回答 3

4
and or x y z //ArrayBuffer[String]

我会避免表示这样的表达式。虽然可以明确地获得前缀概念中的表达式结构,但它并不像拥有递归结构那样容易。

相反,您应该使用递归定义的类层次结构来表示表达式。在不提供太多细节的情况下,您可能会拥有一个接口(aTrait或 abstract Class),以及该接口的实现者,它们取决于参数的数量:一个用于具有三个部分的表达式(如 ((or, x, y)(and, (or x y), z))),一个用于具有两个部分的表达式(like (not, x)),一个用于带有一部分的表达式(like x, y, z, nil, 等)。

然后你的简化过程变成了一个大的模式匹配方法,它可以递归地调用自己来遍历表达式的解析树:

def simplify(expression: ExpressionIterface) = 
    expression match {
        case /* pattern */ => /* result, possibly with a recursive call to simplify */
        ...
    }

编辑:ArrayBuffer[String]可以使用简单的递归解析函数将 转换为您的类,因为您知道每个运算符应该关联多少个参数。您可以遍历缓冲区,每次看到andoror时,您开始创建 3 部分表达式,每次看到 anot时,您开始创建 2 部分表达式,并为其他任何内容创建 1 部分表达式。

于 2012-04-14T02:29:04.503 回答
3

我认为这在Scala by Example 一书中以 PDF 形式提供,可从 scala lang 网站获得(参见第 7 章)。我的建议是使用案例类来表示您的表达式,然后使用模式匹配来简化表达式:

首先,让我们定义一个表达式特征,用于表示各种表达式。

scala> trait Expr { def simplify:Expr = this }
defined trait Expr

在这里,我让 Expr trait 实现了一个默认simplify方法,该方法只返回扩展 trait 的对象。所以让我们添加一些简单的表达式:

scala> case object True extends Expr
defined module True

scala> case object False extends Expr
defined module False

scala> case class Var(name:String) extends Expr { override def toString = name }
defined class Var

True并在你的例子中False代表1和。将用于表示尚无真值的变量,例如您的示例中的 x、y、a 和 b。Var 还覆盖了使打印输出更漂亮的方法:)nilVartoString

现在来看看和/或有点棘手的情况。让我们定义这些:

scala> case class And(a:Expr, b:Expr) extends Expr {
     | override def simplify = (a.simplify, b.simplify) match {
     | case (True,x) => x
     | case (x,True) => x
     | case (False,x) => False
     | case (x,False) => False
     | case (x,y) => And(x,y)
     | }
     | }
defined class And

scala> case class Or(a:Expr, b:Expr) extends Expr {
     | override def simplify = (a.simplify, b.simplify) match {
     | case (True,x) => True
     | case (x,True) => True
     | case (False,x) => x
     | case (x,False) => x
     | case (x,y) => Or(x,y)
     | }
     | }
defined class Or

And并且Or都覆盖特征中的simplify方法Expr并返回其自身及其子表达式的简化版本。现在,这些可用于构建表达式以及更简单的 True、False 和 Var 表达式:

scala> val X = Var("X"); val Y = Var("Y"); val A = Var("A"); val B = Var("B")
X: Var = X
Y: Var = Y
A: Var = A
B: Var = B

scala> And(X, True).simplify
res10: Expr = X

scala> And(X, And(Y, False)).simplify
res11: Expr = False

scala> And(X, Or(Y, False)).simplify
res12: Expr = And(X,Y)

scala> Or(True, And(X, Or(Y, False))).simplify
res13: Expr = True

最后我们为 not 添加一个表达式:

scala> case class Not(a:Expr) extends Expr {
     | override def simplify = a.simplify match {
     | case True => False
     | case False => True
     | case And(x,y) => Or(Not(x),Not(y))
     | case Or(x,y) => And(Not(x),Not(y))
     | case Not(x) => x
     | case x => Not(x)
     | }
     | }
defined class Not

现在我们可以表示您示例中的表达式。但是对于某些表达式,这个 Not case 类不会做一个完整的简化,例如

scala> Not(Or(Not(X),Y)).simplify
res41: Expr = And(Not(Not(X)),Not(Y))

所以我们可以定义一个递归函数Not来尝试简化表达式,直到它不能再简化它:

scala> case class Not(a:Expr) extends Expr {
     | override def simplify = recursiveSimplify(a, a)
     | private def recursiveSimplify(curExpr:Expr, lastExpr:Expr):Expr = if(curExpr != lastExpr) {
     | val newExpr = curExpr.simplify match {
     | case True => False
     | case False => True
     | case Var(x) => Not(Var(x))
     | case Not(x) => x
     | case And(x,y) => Or(Not(x), Not(y))
     | case Or(x,y) => And(Not(x), Not(y))
     | }
     | recursiveSimplify(newExpr, curExpr)
     | } else {
     | lastExpr
     | }
     | }
defined class Not

现在前面的表达式简化为:

scala> Not(Or(Not(X),Y)).simplify
res42: Expr = Or(Not(X),Y)
于 2012-04-14T10:30:43.020 回答
0

这是dhg解决方案的简单实现:

package solve

sealed trait Expr
case class Not(e:Expr) extends Expr
case class And(e1:Expr, e2:Expr) extends Expr
case class Or(e1:Expr, e2:Expr) extends Expr
case class Idn(v:String) extends Expr
object Solve extends App {
  def prep(s:String):List[String] =
    s.replaceAll("[()]+"," ").split(" ").filter(_.size > 0).toList
  def parse(l:List[String]):Expr =
    parseI(l) match {
      case (e,Nil) => e
      case _ => throw new Exception("malformed exception")
    }
  def parseI(l:List[String]):(Expr,List[String]) =
    l match {
      case "not" :: rest =>
        val (e, rem) = parseI(rest)
        (Not(e), rem)
      case "and" :: rest =>
        val (e1, rem) = parseI(rest)
        val (e2, rem2) = parseI(rem)
        (And(e1,e2), rem2)
      case "or" :: rest =>
        val (e1, rem) = parseI(rest)
        val (e2, rem2) = parseI(rem)
        (Or(e1,e2), rem2)
      case i :: rest =>
        (Idn(i), rest)
      case Nil => throw new Exception
    }
  def simplify(e:Expr):Expr = {
    e match {
      case Or(x,Idn("nil")) => simplify(x)
      case Or(Idn("1"),x) => Idn("1")
      case Or(x,y) => Or(simplify(x),simplify(y))
      case x => x
    }
  }  
}

还有一个测试用例:

import org.scalatest.FunSuite
import org.scalatest.matchers.ShouldMatchers
import solve._
import Solve._

class SolveTest extends FunSuite with ShouldMatchers {
  test ("prepare expression") {
    prep("(and(x x))") should equal (List("and","x","x"))
  }
  test ("parse expressions") {
    parse(prep("(and(x x))")) should equal (And(Idn("x"), Idn("x")))
    parse(prep("(or (and x z) y)")) should equal (Or(And(Idn("x"), Idn("z")), Idn("y")))
    parse(prep("(and (or z (not x))(or e a))")) should equal (And(Or(Idn("z"),Not(Idn("x"))),Or(Idn("e"),Idn("a"))))
  }
  test ("simplification") {
    simplify(parse(prep("(or (and x z) nil)"))) should equal (And(Idn("x"),Idn("z")))
  }
}
于 2012-04-14T08:51:59.337 回答