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)と、引数の数に依存するそのインターフェースの実装者があります。1つは(、、(or, x, y)または(and, (or x y), z)))のような3つの部分を持つ式用で、もう1つは2つの部分を持つ式用です。 (など) 、(not, x)および1つの部分(、、、、など)を持つ式用に1つ。xyznil

次に、単純化手順は、式の解析ツリーをトラバースするためにそれ自体を再帰的に呼び出すことができる1つの大きなパターンマッチングメソッドになります。

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

編集:ArrayBuffer[String]各演算子に関連付ける引数の数がわかっているので、をクラスに変換するには、単純な再帰解析関数を使用できます。バッファをトラバースすることができ、andまたはを表示するたびorに3つの部分からなる式の作成をnot開始し、を表示するたびに2つの部分からなる式の作成を開始し、それ以外の場合は1つの部分からなる式を作成します。

于 2012-04-14T02:29:04.503 に答える
3

これは、scala langWebサイトからPDFとして入手できるScalabyExampleの本でカバーされていると思います(第7章を参照)。私の提案は、ケースクラスを使用して式を表現し、パターンマッチングを使用して式を単純化することです。

まず、あらゆる種類の式を表すために使用される式の特性を定義しましょう。

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

ここでは、Exprトレイトにsimplify、トレイトを拡張するオブジェクトを返すだけのデフォルトのメソッドを実装させました。それでは、いくつかの簡単な式を追加しましょう。

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はとを表します。まだ真理値を持たない変数を表すために使用されます。たとえば、例ではx、y、a、bです。Varはまた、印刷を少しきれいにする方法を上書きします:)1nilVartoString

さて、および/またはで少しトリッキーな状況になります。これらを次のように定義しましょう:

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オーバーライドし、それら自体とそのサブエクスプレッションの簡略化されたバージョンを返します。これで、これらを使用して、より単純なTrue、False、およびVar式とともに式を作成できます。simplifyExpr

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

これで、例の式を表すことができます。ただし、一部の式では、このNotcaseクラスは完全な単純化を行いません。

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 に答える