为了账号安全,请及时绑定邮箱和手机立即绑定

scala中的部分应用函数和偏函数的区别?

scala中的部分应用函数和偏函数的区别?

慕姐8265434 2019-02-25 10:06:10
scala中的部分应用函数和偏函数的区别
查看完整描述

2 回答

?
慕森王

TA贡献1777条经验 获得超3个赞

部分应用函数和偏函数是无关的。经常把部分应用函数(Partial Applied Function)和偏函数(Partial Function) 搞混。
总结如下:
部分应用函数(Partial Applied Function)是缺少部分参数的函数,是一个逻辑上概念

偏函数是只对函数定义域的一个子集进行定义的函数。 scala中用scala.PartialFunction[-T, +S]类来表示
比如定义了一个函数:def sum(x: Int)(y: Int) = x + y, 当调用sum的时候,如果不提供所有的参数或某些参数还未知时,比如sum _ , sum(3)(_: Int), sum(_: Int)(3), 这样就生成了所谓的部分应用函数。部分应用函数只是逻辑上的一个表达,scala编译器会用Function1, Function2这些类来表示它.
下面这个变量signal引用了一个偏函数
val signal: PartialFunction[Int, Int] = {
case x if x > 1 => 1
case x if x < -1 => -1
}
这个signal所引用的函数除了0值外,对所有整数都定义了相应的操作。 signal(0) 会抛出异常,因此使用前最好先signal.isDefinedAt(0)判断一下。 偏函数主要用于这样一种场景:对某些值现在还无法给出具体的操作(即需求还不明朗),也有可能存在几种处理方式(视乎具体的需求);我们可以先对需求明确的部分进行定义,比如上述除了0外的所有整数域,然后根据具体情况补充对其他域的定义,比如 :
val composed_signal: PartialFunction[Int,Int] = signal.orElse{
case 0 => 0
}
composed_signal(0) // 返回 0
或者对定义域进行一定的偏移(假如需求做了变更, 1 为无效的点)
val new_signal: Function1[Int, Int] = signal.compose{
case x => x - 1
}
new_signal(1) // throw exception
new_signal(0) // 返回 -1
new_signal(2) // 返回 1
还可以用andThen将两个相关的偏函数串接起来
val another_signal: PartialFunction[Int, Int] = {
case 0 => 0
case x if x > 0 => x - 1
case x if x < 0 => x + 1
}
val then_signal = another_signal andThen signal
这里的then_signal 剔除了-1, 0, 1三个点的定义



查看完整回答
反对 回复 2019-03-27
?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

部分应用函数:
  你还可以使用单个“_”替换整个参数列表。例如可以写成:
  List(1,2,3,4,5).foreach(println(_))
  或者更好的方法是你还可以写成:
  List(1,2,3,4,5).foreach(println _)
  以这种方式使用下划线时,你就正在写一个部分应用函数。部分应用函数是一种表达式,你不需要提供函数需要的所有参数,代之以仅提供部分,或不提供所需参数。如下先定义一个函数,然后创建一个部分应用函数,并保存于变量,然后该变量就可以作为函数使用:
  def sum(a: Int, b: Int, c: Int) = a + b + c
  val a = sum _
  println(a(1,2,3))
  实际发生的事情是这样的:名为a的变量指向一个函数值对象,这个函数值是由scala编译器依照部分应用函数表达式sum _,自动产生的类的一个实例。编译器产生的类有一个apply方法带有3个参数(之所以带3个参数是因为sum _表达式缺少的参数数量为3),然后scala编译器把表达式a(1,2,3)翻译成对函数值的apply方法的调用。你可以使用这种方式把成员函数和本地函数转换为函数值,进而在函数中使用它们。不过,你还可以通过提供某些但不是全部需要的参数表达一个部分应用函数。如下,此变量在使用的时候,可以仅提供一个参数:
  val b = sum(1, _: Int, 3)
  如果你正在写一个省略所有参数的部分应用函数表达式,如println _或sum _,而且在代码的那个地方正需要一个函数,你就可以省略掉下划线(不是需要函数的地方,你这样写,编译器可能会把它当作一个函数调用,因为在scala中,调用无副作用的函数时,默认不加括号)。如下代码就是:
  List(1,2,3,4,5).foreach(println)

偏函数:
  偏函数和部分应用函数是无关的。偏函数是只对函数定义域的一个子集进行定义的函数。scala中用scala.PartialFunction[-T,+S]来表示。偏函数主要用于这样一种场景:对某些值现在还无法给出具体的操作(即需求还不明朗),也有可能存在几种处理方式(视乎具体的需求),我们可以先对需求明确的部分进行定义,以后可以再对定义域进行修改。PartialFunction中可以使用的方法如下:
  isDefinedAt:判断定义域是否包含指定的输入。
  orElse:补充对其他域的定义。
  compose:组合其他函数形成一个新的函数,假设有两个函数f和g,那么表达式f _ compose g _则会形成一个f(g(x))形式的新函数。你可以使用该方法对定义域进行一定的偏移。
  andThen:将两个相关的偏函数串接起来,调用顺序是先调用第一个函数,然后调用第二个,假设有两个函数f和g,那么表达式f _ andThen g _则会形成一个g(f(x))形式的新函数,刚好与compose相反。



查看完整回答
反对 回复 2019-03-27
  • 2 回答
  • 0 关注
  • 877 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信