2013-01-14 37 views
3

假設我有我的代碼中定義了一些布爾謂詞:創建一個返回邏輯的幾個布爾謂詞或函數

def pred1[A](x: A): Boolean = { ... } 
def pred2[A](x: A): Boolean = { ... } 
def pred3[A](x: A): Boolean = { ... } 

現在,我希望能夠創建一個函數,例如,pred1pred3的邏輯或。

所以,像這樣:

def pred1Or3[A](x: A) = or(pred1, pred2) 

更妙的是,它會是不錯的能夠一概而論,這樣我可以提供我自己的組合功能。所以,如果不是,我想有邏輯AND,我稱之爲:

def pred1And3[A](x: A) = combine({_ && _}, pred1, pred2) 

我可以達到同樣的效果基本是這樣的:

def pred1And3[A](x: A) = Seq(pred1, pred2) map { _(x) } reduce { _ && _ } 

,但似乎有點冗長和雲意圖。在Scala中有更簡單的方法嗎?

+0

[Applicatives(http://stackoverflow.com/q/13437773/1346276)解決一般情況,但我不確定它們是否可以在Scala中實現。 – phg

回答

6

這裏有一個解決方案,簡單,並允許在同一傳遞物品的可變數目時間。我已經給這兩個or情況下和更通用combine情況:

def or[A](ps: (A => Boolean)*) = 
    (a: A) => ps.exists(_(a)) 

def combine[A](ps: (A => Boolean)*)(op: (Boolean, Boolean) => Boolean) = 
    (a: A) => ps.map(_(a)).reduce(op) 

下面是一些例子用法:

// "or" two functions 
val pred1or3 = or(pred1, pred3)     
pred1or3("the") 

// "or" three functions 
val pred12or3 = or(pred1, pred2, pred3)   
pred12or3("the") 

// apply a dijoined rule directly 
or(pred1, pred2, pred3)("the")     

// combine two functions with "and" 
val pred12and3 = combine(pred1, pred3)(_ && _) 
pred12and3("the") 

// apply a conjoined rule directly 
combine(pred1, pred2, pred3)(_ && _)("the")  

// stack functions as desired (this is "(pred1 || pred3) && (pred1 || pred2)") 
combine(or(pred1, pred3), or(pred1, pred2))(_ && _)("a") 
+0

這種解決方案正是我想到的。我肯定希望能夠組合不定數量的謂詞。不過,我很驚訝這已經不在Scala中。 –

+0

嗨馬克!噢,但是,它隱藏在Scala的函數式編程庫中:scalaz,示例和解釋可以在這裏找到:http://voidmainargs.blogspot.de/2012/02/having-fun-with-monoid-in-scalaz- seven.html?m = 1 – AndreasScheinert

1
def or[A](p: A => Boolean, q: A => Boolean) = (a: A) => p(a) || q(a) 
def logic[A](p: A => Boolean, q: A => Boolean)(c: (Boolean, Boolean) => Boolean) = { 
    (a: A) => c(p(a) , q(a)) 
} 

你可以一個參數(a: A)添加到這些方法不是返回功能,例如:

def or2[A](a: A)(p: A => Boolean, q: A => Boolean) = p(a) || q(a) 
4

下面是我在過去使用的解決方案:

implicit def wrapPredicates[A](f: A => Boolean) = new { 
    def <|>(g: A => Boolean) = (x: A) => f(x) || g(x) 
    def <&>(g: A => Boolean) = (x: A) => f(x) && g(x) 
} 

使用方法如下:

val pred12or3 = pred1 <|> pred2 <|> pred3 
+0

這是一個有趣且靈活的方法。它介紹了我想稱之爲「字母組合」和「字母組合」的操作符。 –

+0

這很完美。正是我想要做的。但你過去是什麼意思?你有沒有找到更好的? – Ebuall

2

這裏有一個解決方案,失敗快,但並不像一般:

def or[A](ps: (A => Boolean)*) = (a:A) => ps.exists(_(a)) 
def and[A](ps: (A => Boolean)*) = (a:A) => ps.forall(_(a)) 

樣品會議

scala> def or[A](ps: (A => Boolean)*) = (a:A) => ps.exists(_(a)) 
or: [A](ps: A => Boolean*)A => Boolean 
scala> or((x:Int) => {println("a");x > 5}, (x:Int) => {println("b");x < 2}) 
res6: Int => Boolean = <function1>  
scala> res6(1) 
a 
b 
res7: Boolean = true  
scala> res6(6) 
a 
res8: Boolean = true