Algorithm 如何去掉带有AND和OR的布尔表达式中的大括号

Algorithm 如何去掉带有AND和OR的布尔表达式中的大括号,algorithm,scala,abstract-syntax-tree,boolean-logic,algebraic-data-types,Algorithm,Scala,Abstract Syntax Tree,Boolean Logic,Algebraic Data Types,假设我有一个简单的布尔表达式 (A || B) && (C || D) 例如,目标是去掉这个表达式中的大括号 (A || B) && (C || D) => A && C || A && D || B && C || B && D 我们知道&&在|之前从左到右求值。 为此,我创建了以下代数数据类型: sealed trait Predicate case class Or(left: Pre

假设我有一个简单的布尔表达式

(A || B) && (C || D)
例如,目标是去掉这个表达式中的大括号

(A || B) && (C || D) => A && C || A && D || B && C || B && D
我们知道
&&
|
之前从左到右求值。 为此,我创建了以下代数数据类型:

sealed trait Predicate
case class Or(left: Predicate, right: Predicate) extends Predicate
case class And(left: Predicate, right: Predicate) extends Predicate
case object True extends Predicate
case object False extends Predicate
让我们假设我们已经有了某种字符串解析器,它将字符串转换为
谓词
,它构建了某种抽象语法树。 例如,对于表达式
(true | | true)和&(true | | true)
我们将有以下树:
和(或(或(真,真),或(真,真))
。这里我们要考虑大括号。我们需要得到
或(或(和(A,C)和(A,D)),或(和(B,C)和(B,D))
。 我坚持使用以下解决方案:

def extractOr(pred: Predicate): Predicate = pred match {
    case And(Or(l, r), Or(ll, rr)) => Or(Or(And(l, ll), And(l, rr)), Or(And(r, ll), And(r, rr)))
    case And(Or(l, r), p) => Or(And(l, p), And(r, p))
    case And(p, Or(l, r)) => Or(And(p, l), And(p, r))
    case p => p
}

def popOrPredicateUp(pred: Predicate): Predicate = pred match {
    case And(l, r) => extractOr(And(popOrPredicateUp(l), popOrPredicateUp(r)))
    case Or(l, r) => Or(popOrPredicateUp(l), popOrPredicateUp(r))
    case p => p
}
sealed trait Predicate
case class Or(left: Predicate, right: Predicate) extends Predicate
case class And(left: Predicate, right: Predicate) extends Predicate
case class Not(pred: Predicate) extends Predicate
case object True extends Predicate
case object False extends Predicate

object PredicateOps{

  def toNNF(pred: Predicate): Predicate = pred match {
    case a @ (True | False) => a
    case a @ Not( True | False) => a
    case Not(Not(p)) => p
    case And(l, r) => And(toNNF(l), toNNF(r))
    case Not(And(l, r)) => toNNF( Or(Not(l), Not(r)))
    case Or(l, r) => Or(toNNF(l), toNNF(r))
    case Not(Or(l,r)) => toNNF( And(Not(l), Not(r)))
  }

  def dist(predL: Predicate, predR: Predicate): Predicate = (predL, predR) match {
    case (Or(l, r), p) => Or(dist(l, p), dist(r, p))
    case (p, Or(l, r)) => Or(dist(p, l), dist(p, r))
    case (l, r) => And(l, r)
  }

  def toDNF(pred: Predicate): Predicate = pred match {
    case And(l, r) => dist(toDNF(l), toDNF(r))
    case Or(l, r) =>  Or(toDNF(l), toDNF(r))
    case p => p
  }

}
但它不正确,例如在这种情况下:
And(False,Or(And(Or(True,True),False),True))


UPD:正如@coredump所指出的,我需要得到@coredump(他指出了正确的方向)和Haskell包(特别是它)的大力帮助,才能最终获得。我得出了以下解决方案:

def extractOr(pred: Predicate): Predicate = pred match {
    case And(Or(l, r), Or(ll, rr)) => Or(Or(And(l, ll), And(l, rr)), Or(And(r, ll), And(r, rr)))
    case And(Or(l, r), p) => Or(And(l, p), And(r, p))
    case And(p, Or(l, r)) => Or(And(p, l), And(p, r))
    case p => p
}

def popOrPredicateUp(pred: Predicate): Predicate = pred match {
    case And(l, r) => extractOr(And(popOrPredicateUp(l), popOrPredicateUp(r)))
    case Or(l, r) => Or(popOrPredicateUp(l), popOrPredicateUp(r))
    case p => p
}
sealed trait Predicate
case class Or(left: Predicate, right: Predicate) extends Predicate
case class And(left: Predicate, right: Predicate) extends Predicate
case class Not(pred: Predicate) extends Predicate
case object True extends Predicate
case object False extends Predicate

object PredicateOps{

  def toNNF(pred: Predicate): Predicate = pred match {
    case a @ (True | False) => a
    case a @ Not( True | False) => a
    case Not(Not(p)) => p
    case And(l, r) => And(toNNF(l), toNNF(r))
    case Not(And(l, r)) => toNNF( Or(Not(l), Not(r)))
    case Or(l, r) => Or(toNNF(l), toNNF(r))
    case Not(Or(l,r)) => toNNF( And(Not(l), Not(r)))
  }

  def dist(predL: Predicate, predR: Predicate): Predicate = (predL, predR) match {
    case (Or(l, r), p) => Or(dist(l, p), dist(r, p))
    case (p, Or(l, r)) => Or(dist(p, l), dist(p, r))
    case (l, r) => And(l, r)
  }

  def toDNF(pred: Predicate): Predicate = pred match {
    case And(l, r) => dist(toDNF(l), toDNF(r))
    case Or(l, r) =>  Or(toDNF(l), toDNF(r))
    case p => p
  }

}
以下是它的工作原理:

val expr = And(False, Or(And(Or(True, True), False), True))
val dnf = (PredicateOps.toNNF _ andThen PredicateOps.toDNF _).apply(expr)
println(dnf)

和输出
或(或(和(假,和(真,假))和(假,和(真,假)))和(假,真))
哪个是正确的DNF。

根据你的标题问题和介绍,一开始不清楚你是想计算还是想以某种方式重构你的代码。或者也许你根本不想要DNF。这是作业吗?@coredump:DNF(产品总和)-这正是我要找的!好的观点。在“And(False,Or(And(Or(True,True),False),True))”中,你不想让它立即短路到False吗,因为如果一个实例中有1个False,它的计算结果为False?@Bobas_Pett No,我只想创建“乘积之和”,而不需要实际计算。在实际应用中,我使用了一些布尔函数(规则),而不是“真”或“假”。任何复杂术语的DNF都可能是巨大的。你为什么不消除涉及真或假的术语,你可以对它们进行评估,从而使结果更小?[您的示例将产生FALSE]@IraBaxter解决方案的最终目标不是评估整个语句,而是将语句拆分为析取子句。。我明白这一点(我已经构建了这样的析取构建器)。规模的膨胀可以是惊人的(指数);我们发现我们需要所有能得到的帮助来管理尺寸。重言式的术语是。。。没用。如果表单包含变量(其中包含变量),此优化不会阻止您扩展表单。