2017-06-14 108 views
0

我有兩個部分函數返回單元(f1,f2)。舉例來說,這樣的事情:組合2部分函數

val f1 = { 
    case s: arg => //do some 
    //etc... lots of cases 
} 

val f2 = { 
    case s: anotherArg => //do some 
    //lots of cases 
} 

有撰寫這部分功能的方式,一個簡潔的方式,如果

f(x) = {f1(x); f2(x)} iff f1.isDefinedAt(x) && f2.isDefinedAt(x) 
f(x) = f1(x); iff f1.isDefinedAt(x) && !f2.isDefinedAt(x) 
f(x) = f2(x); iff !f1.isDefinedAt(x) && f2.isDefinedAt(x) 
+0

如果我明白你要做什麼,如果'f1()'和'f2()'定義了'x',那麼你只是在運行'f1()'來獲得副作用?即,結果將被丟棄? –

回答

3

否則容易

f1 orElse f2 

斯卡拉REPL

scala> val f: PartialFunction[Int, Int] = { case 1 => 1 } 
f: PartialFunction[Int,Int] = <function1> 

scala> val g: PartialFunction[Int, Int] = { case 2 => 2 } 
g: PartialFunction[Int,Int] = <function1> 

scala> val h = f orElse g 
h: PartialFunction[Int,Int] = <function1> 

scala> h(1) 
res3: Int = 1 

scala> h(2) 
res4: Int = 2 

scala> h.isDefinedAt(1) 
res6: Boolean = true 

scala> h.isDefinedAt(2) 
res7: Boolean = true 

兩個兩個函數來執行共同的情況下

使用的部分功能和foldLeft列表

斯卡拉REPL

scala> val f: PartialFunction[Int, Int] = { case 1 => 1 case 3 => 3} 
f: PartialFunction[Int,Int] = <function1> 

scala> val g: PartialFunction[Int, Int] = { case 2 => 2 case 3 => 3} 
g: PartialFunction[Int,Int] = <function1> 

scala> val h = f orElse g 
h: PartialFunction[Int,Int] = <function1> 

scala> h(3) 
res10: Int = 3 

scala> h(3) 
res11: Int = 3 

scala> val h = List(f, g) 
h: List[PartialFunction[Int,Int]] = List(<function1>, <function1>) 

scala> def i(arg: Int) = h.foldLeft(0){(result, f) => if (f.isDefinedAt(arg)) result + f(arg) else result } 
i: (arg: Int)Int 

scala> i(3) 
res12: Int = 6 
+0

不完全......但如果他們都定義爲某個值呢?例如在3?我想他們都援引。 –

+0

@聖安達里奧你可以做一點小小的調整。讓我編輯答案\ – pamu

+0

@ St.Antario請看看。剛使用了foldLeft的部分函數列表 – pamu

1

雖然pamu的回答是不錯的,我不喜歡的事實,它必然會特定的Int類型。不幸的是你沒有指定結果類型不夠好,所以我看到3個備選方案:

  1. 你想獲得的所有定義的函數的所有結果的列表,你不關心哪個函數產生哪些結果。在這種情況下,像這樣的工作:
def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldRight(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc) 

如果元素的順序並不重要,你可以使用

def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldLeft(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc) 

這可能會更快一點

  • 如果您在相應的功能被定義爲,您想要獲得OptionSome否則爲。在這種情況下,像這樣的工作:
  • def callAllOption[A, B](funcs: List[PartialFunction[A, B]], a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a)) 
    

    如果你不想明確創建List,你可以使用可變參數,如:

    def callAllOptionVarArg[A, B](a: A, funcs: PartialFunction[A, B]*): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList 
    

    或咖喱等版本的指定值功能之後:

    def callAllOptionVarArg2[A, B](funcs: PartialFunction[A, B]*)(a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList 
    
  • 你打電話純粹是爲了副作用和返回功能值並不重要,在這種情況下,可以安全地使用第二(有點快)callAll定義
  • 實例:

    val f: PartialFunction[Int, Int] = { 
        case 1 => 1 
        case 3 => 3 
    } 
    val g: PartialFunction[Int, Int] = { 
        case 2 => 2 
        case 3 => 4 
    } 
    
    val fl = List(f, g) 
    println(callAll(fl, 1)) 
    println(callAll(fl, 3)) 
    println(callAllOption(fl, 2)) 
    println(callAllOptionVarArg(1, f, g)) 
    println(callAllOptionVarArg2(f, g)(3)) 
    

    列表(1)
    列表(3,4)
    列表(無,一些(2))
    列表(一些(1),無)
    列表(一些(3),一些(4))