2017-06-14 144 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))