Scala-偏函数与部分应用函数

来源:互联网 发布:云计算优缺点 编辑:程序博客网 时间:2024/04/29 00:30

scala中有PartialFunction的概念, 同时还要一个概念叫Partial Applied Function. 前者译作偏函数, 后者译作"偏应用函数"或"部分应用函数", 一字之差, 差距很大.

1.偏函数

首先我们介绍样本序列(Case sequences),从而具体介绍什么是偏函数。样本序列是一种特殊的函数,通常情况下函数只有一个入口,但是样本序列会有多个函数入口。比如下面的列子:
val withDefault: Option[Int] => Int = {      case Some(x) => x      case None => 0}
withDefault是一个(Option[Int] => Int)类型的方法,这个方法体保护2个case.第一个匹配Some类型,第二个匹配None类型
scala> withDefault(Some(10))res28: Int = 10  scala> withDefault(None)res29: Int = 0
这种方法的使用在Akka的actor中经常使用到,比如actor中的receive方法
def receive = {    case Data(byte) =>      sum += byte      case GetChecksum(requester) =>      val checksum = ~(sum & 0xFF) + 1      requester ! checksum}
如果,你传递的参数值是case里面无法匹配的,它将会产生一个运行时的异常,比如
val second: List[Int] => Int = {case x :: y :: _ => y}scala> second(List())scala.MatchError: List()at $anonfun$1.apply(<console>:17)at $anonfun$1.apply(<console>:17)
注意此时的second还仅是一个函数类型,具体来说它是一个function1类型 ,如果你想定义一个偏函数函数必须进行如下的声明 (function1和PartialFunction的区别稍后讲解)
val second2: PartialFunction[List[Int],Int] = {  case x :: y :: _ => y}
事实上,这个字面函数{ case x :: y :: _ => y }在编译时会翻译成下面的语句,但是如果你的类型声明是Funtion1或者缺失,它可能会翻译成一个不完整的函数,所以推荐使用完整的
PartialFunction声明,如上面的例子
new PartialFunction[List[Int], Int] {  def apply(xs: List[Int]) = xs match {case x :: y :: _ => y  }  def isDefinedAt(xs: List[Int]) = xs match {case x :: y :: _ => truecase _ => false  }}
只有当isDefinedAt方法返回为true是,apply方法才会去执行,此时我们可以添加额外的逻辑,比如过滤掉某些不符合条件的东东
val list=List(List(1,2),List(1))val r1=list.collect(second2) //collect有个重载的方法参数为PartialFunctionprintln(r1) //List(2)

function1和PartialFunction的区别

其实官方的API解释得很明朗,通俗点来说平时我们使用的拉姆达表达式就是FunctionX提供给我们的语法糖,二者的功能完全一样。事实上,PartialFunction是Funtion1的子类,只不过Funtion1仅仅只是一个函数,而PartialFunction可以识别出我们的输入,并进行一些额外的处理

A function of 1 parameter.

In the following example, the definition of succ is a shorthand for the anonymous class definition anonfun1:

 object Main extends App {   val succ = (x: Int) => x + 1   val anonfun1 = new Function1[Int, Int] {     def apply(x: Int): Int = x + 1   }   assert(succ(0) == anonfun1(0))}

Note that the difference between Function1 and scala.PartialFunction is that the latter can specify inputs which it will not handle.


2.部分应用函数

部分应用函数, 是指一个函数有N个参数, 而我们为其提供少于N个参数, 那就得到了一个部分应用函数. 

比如我先定义一个函数

def sum(a:Int,b:Int,c:Int) = a + b + c; 
那么就可以从这个函数衍生出一个偏函数是这样的:
def p_sum = sum(1, _:Int, _:Int)
于是就可以这样调用p_sum(2,3), 相当于调用sum(1,2,3) 得到的结果是6. 这里的两个_分别对应函数sum对应位置的参数. 所以你也可以定义成
def p_sum = sum (_:Int, 1, _:Int) 
0 0
原创粉丝点击