2010-08-29 328 views
2

我只是在尋找更好的Scala處事方法,所以問了一些新手問題。例如:如何減少布爾函數定義中的冗餘?

我希望能夠做的事情如下所示:

鑑於A,B,C分別是 「布爾」:

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

在那裏我會循環可能的一個, 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,nor等...可以使用布爾值就好了。

我認爲我的主要也呼籲減少冗餘,我在幾行使用不同的功能......但唯一改變的是函數名稱。

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

回答

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在JITs代碼時適當地優化對象構造。

4

正如肯布魯姆,我建議使用隱式轉換來保存所有的輸入。在另一個方向進行轉換(MyBoolean - > 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(因爲這已經爲案例對象和類實施)。

[編輯]的實現考慮肯的言論:

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 
} 
+0

好主意,除非你已經通過使用圖案的元組每個操作匹配扔掉你的優勢。當你擁有的只有一個操作時,這就創建了一個額外的對象!此外,不匹配至少是一樣的:'def和(that:MyBoolean)= if((this eq TRUE)&&(that eq TRUE))TRUE else FALSE' – 2010-08-29 14:29:17

+0

是的,這樣會更快。對於真實世界的實現,可能所有的方法都應該用這種方式編寫(需要隱式轉換否定等也不好)。 – Landei 2010-08-29 15:43:05

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 
} 
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)) 
    } 
}