结合2个部分功能

时间:2017-06-14 13:12:48

标签: scala function

我有两个部分函数返回单位(f1f2)。例如,类似的东西:

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) 

2 个答案:

答案 0 :(得分:4)

orElse

f1 orElse f2

Scala 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

Scala 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

答案 1 :(得分:1)

尽管pamu的答案很好,但我不喜欢它与特定Int类型绑定的事实。不幸的是,你没有足够好地指定结果类型,所以我看到了3个替代方案:

  1. 您希望获得所有已定义函数的所有结果的列表,并且您不关心哪个函数产生了哪些结果。在这种情况下,这样的事情会起作用:
  2. 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)
    

    可能会更快一点

    1. 如果在该点定义了相应的函数,则希望Option获得Some,否则None。在这种情况下,这样的事情会起作用:
    2. def callAllOption[A, B](funcs: List[PartialFunction[A, B]], a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a))
      

      如果您不想明确创建List,可以使用varargs,例如:

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

      或这样的curried版本,用于指定函数后的值:

      def callAllOptionVarArg2[A, B](funcs: PartialFunction[A, B]*)(a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList
      
      1. 你纯粹为副作用调用函数,返回值并不重要,在这种情况下你可以安全地使用第二个(更快一点)callAll定义
      2. 示例:

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