如何减少以下布尔函数定义中的冗余?

时间:2010-08-29 03:54:23

标签: scala

我只是在寻找更好的Scala做事方式,所以问新手问题。例如:

我希望能够做到以下几点:

给定a,b,c为“boolean”:

if (((a nand b) nand c) != (a nand (b nand c))) printf("NAND is not associative")

我将循环浏览可能的a,b,c布尔值。我是这样做的:

for (i <- 0 to 7) {
  val (a,b,c) = (new MyBoolean((i & 4) >> 2 == 1),
                 new MyBoolean((i & 2) >> 1 == 1),
                 new MyBoolean((i & 1) == 1))
  printf("%d (%s,%s,%s)\n",i,a,b,c)
  if (((a nand b) nand c) != (a nand (b nand c))) printf("NAND\n")
}

我想我可以简化一下:

val (a,b,c) = (new MyBoolean(i & 4 != 0),
               new MyBoolean(i & 2 != 0),
               new MyBoolean(i & 1 != 0))

我的MyBoolean类看起来像:

class MyBoolean(val p: Boolean) {
  def and(q: MyBoolean): MyBoolean = new MyBoolean(p && q.p)
  override def toString: String = p.toString
  override def equals (o : Any): Boolean = o match {
      case m : MyBoolean => p == m.p
      case _ => false
  }
  def and(q: Boolean): MyBoolean = new MyBoolean(p && q)
  def or(q: Boolean): MyBoolean = new MyBoolean(p || q)
  def or(q: MyBoolean): MyBoolean = or(q.p)
  def negate: MyBoolean = new MyBoolean(!p)
  def nand(q : Boolean): MyBoolean = new MyBoolean(!(p && q))
  def nand(q : MyBoolean): MyBoolean = nand(q.p)
  def nor(q : Boolean): MyBoolean = new MyBoolean(!(p || q))
  def nor(q : MyBoolean): MyBoolean = nor(q.p)
  def xor(q : Boolean): MyBoolean = new MyBoolean((p || q) && !(p && q))
  def xor(q : MyBoolean): MyBoolean = xor(q.p)
  def implies(q : Boolean): MyBoolean = new MyBoolean(!(p && !q))
  def implies(q : MyBoolean): MyBoolean = implies(q.p)
  def equiv(q : Boolean): MyBoolean = new MyBoolean(p == q)
  def equiv(q : MyBoolean): MyBoolean = equiv(q.p)
}

这是合理的,还是有更好的方法来解决这个问题? :)

我没有运气尝试过:

def nand(p : Boolean, q : Boolean): Boolean = !(p && q)

我不能从那里去:

(a nand (b nand c))

正如我所希望的那样(反对希望)。 :)我真的宁愿不介绍一个新类型,只要有nand,也不是等等就好了...使用布尔值。

我认为我的主要人员也呼吁减少冗余,我在几行使用不同的功能......但唯一改变的是功能名称。

def main(args: Array[String]): Unit = {
 for (i <- 0 to 7) {
  val (a,b,c) = (new MyBoolean((i & 4) != 0),
                 new MyBoolean((i & 2) != 0),
                 new MyBoolean((i & 1) != 0))
  printf("%d (%s,%s,%s)\n",i,a,b,c)
  if (((a nand b) nand c) != (a nand (b nand c))) printf("NAND\n")
  if (((a implies b) implies c) != (a implies (b implies c))) printf("IMPLIES\n")
  if (((a nor b) nor c) != (a nor (b nor c))) printf("NOR\n")
  if (((a xor b) xor c) != (a xor (b xor c))) printf("XOR\n")
  if (((a equiv b) equiv c) != (a equiv (b equiv c))) printf("EQUIV\n")
 }
}

-Jay

4 个答案:

答案 0 :(得分:8)

你应该为此使用隐式转换,如下所示:

class MyBoolean {/*...*/} 
implicit def decorateBoolean(x:Boolean) = new MyBoolean(x)

for (i <- 0 to 7) {
  val (a,b,c) = ((i & 4) != 0,
                 (i & 2) != 0,
                 (i & 1) != 0)
  printf("%d (%s,%s,%s)\n",i,a,b,c)
  if (((a nand b) nand c) != (a nand (b nand c))) printf("NAND\n")
}

您现在已从源代码中删除了对象构造的语法包袱。 您只需希望JVM在JIT代码时适当地优化对象构造。

答案 1 :(得分:4)

作为Ken Bloom,我建议使用隐式转换来保存所有输入内容。在另一个方向上进行转换(MyBoolean - &gt; Boolean)也很方便。

当你拥有两个不同的值时,创建一个新实例是非常非常浪费的。如果对这些实例使用两个对象,则不再需要对原始布尔类型的任何引用。

以下是我的写作方式:

sealed trait MyBoolean {
  import MyBoolean._

  def and(that: MyBoolean): MyBoolean = (this, that) match {
    case (TRUE,TRUE) => TRUE
    case _ => FALSE
  }

  def or(that: MyBoolean): MyBoolean = (this, that) match {
    case (FALSE, FALSE) => FALSE
    case _ => TRUE
  }

  def negate: MyBoolean = this != TRUE
  def nand(that: MyBoolean): MyBoolean = (this and that).negate
  def nor(that: MyBoolean): MyBoolean = (this or that).negate
  def xor(that: MyBoolean): MyBoolean = this != that
  def implies(that: MyBoolean): MyBoolean = (this and that.negate).negate
  def equiv(that: MyBoolean): MyBoolean = this == that
}

case object TRUE extends MyBoolean
case object FALSE extends MyBoolean

object MyBoolean {
  implicit def bool2MyBool(p:Boolean):MyBoolean = MyBoolean(p)
  implicit def myBool2bool(m:MyBoolean):Boolean = m == TRUE
  def apply(p:Boolean):MyBoolean = if (p) TRUE else FALSE
}

请注意,您不需要equals(因为我们现在可以依赖于对象标识)和toString(因为这已经为case对象和类实现了)。

[编辑] 考虑肯的评论的实现:

sealed trait MyBoolean {
  def and(that: MyBoolean): MyBoolean
  def or(that: MyBoolean): MyBoolean
  def negate: MyBoolean
  def equiv(that: MyBoolean): MyBoolean = if (this == that) TRUE else FALSE
  def nand(that: MyBoolean): MyBoolean = (this and that).negate
  def nor(that: MyBoolean): MyBoolean = (this or that).negate
  def xor(that: MyBoolean): MyBoolean = (this equiv that).negate
  def implies(that: MyBoolean): MyBoolean = (this and that.negate).negate
}

case object TRUE extends MyBoolean {
  def negate = FALSE
  def and(that:MyBoolean) = that
  def or(that:MyBoolean) = this
}
case object FALSE extends MyBoolean {
  def negate = TRUE
  def and(that:MyBoolean) = this
  def or(that:MyBoolean) = that
}

object MyBoolean {
  implicit def bool2MyBool(p:Boolean):MyBoolean = MyBoolean(p)
  implicit def myBool2bool(m:MyBoolean):Boolean = m == TRUE
  def apply(p:Boolean):MyBoolean = if (p) TRUE else FALSE
}

答案 2 :(得分:2)

这是对Landei的回答的改进,基于Ruby的做法:

sealed trait MyBoolean {
  val toBoolean:Boolean
  def and(that: MyBoolean): MyBoolean
  def or(that: MyBoolean): MyBoolean
  def negate: MyBoolean
  def nand(that: MyBoolean): MyBoolean
  def nor(that: MyBoolean): MyBoolean
  def xor(that: MyBoolean): MyBoolean
  def implies(that: MyBoolean): MyBoolean
  def equiv(that: MyBoolean): MyBoolean
}

case object TRUE extends MyBoolean{
   override val toBoolean = true
   override def and(that:MyBoolean) = that
   override def or(that:MyBoolean) = TRUE
   override def negate: MyBoolean = FALSE
   override def nand(that:MyBoolean) = that.negate
   override def nor(that:MyBoolean) = FALSE
   override def xor(that:MyBoolean) = that.negate
   override def implies(that:MyBoolean) = that
   override def equiv(that:MyBoolean) = that
}

case object FALSE extends MyBoolean{
   override val toBoolean = false
   override def and(that:MyBoolean) = FALSE
   override def or(that:MyBoolean) = that
   override def negate: MyBoolean = TRUE
   override def nand(that:MyBoolean) = TRUE
   override def nor(that:MyBoolean) = that.negate
   override def xor(that:MyBoolean) = that
   override def implies(that:MyBoolean) = TRUE
   override def equiv(that:MyBoolean) = that.negate
}

object MyBoolean {
  implicit def bool2MyBool(p:Boolean):MyBoolean = MyBoolean(p)
  implicit def myBool2bool(m:MyBoolean):Boolean = m.toBoolean
  def apply(p:Boolean):MyBoolean = if (p) TRUE else FALSE
}

答案 3 :(得分:0)

我需要了解数据类型转换的工作原理,以及特征的细节。我现在在做什么(代码非常类似于我发现的http://scalasolutions.wordpress.com/2010/07/22/p46-truth-tables-for-logical-expressions/):

object Logic {
  type T = Boolean

  def and(p : T, q : T) = p && q
  def or(p : T, q : T) = p || q
  def negate(p : T) = !p
  def nand(p : T, q : T) = !(p && q)
  def nor(p : T, q : T) = !(p || q)
  def xor(p : T, q : T) = p != q
  def implies(p : T, q : T) = !(p && !q)
  def equiv(p : T, q : T) = p == q
}

def main(args: Array[String]): Unit = {
  import Logic._
  type T = ((Boolean, Boolean) => Boolean, String)
  val checklist =
    List((nand, "NAND\n") : T, (implies, "IMPLIES\n") : T, (nor, "NOR\n") : T,
   (xor, "XOR\n") : T, (equiv, "EQUIV\n") : T)
  // Check associativity of boolean operators does a+(b+c) = (a+b)+c ?
  for (i <- 0 to 7) {
    val (a,b,c) = ((i & 4) != 0, (i & 2) != 0, (i & 1) != 0)
    printf("%d (%s,%s,%s)\n",i,a,b,c)
    checklist.foreach(t => if (t._1(t._1(a,b),c) != t._1(a,t._1(b,c))) printf(t._2))
  }
}