16_Scala_函数式编程高级_偏函数_高级函数_闭包柯里化_递归

举报
alexsully 发表于 2021/05/11 19:52:30 2021/05/11
【摘要】 偏函数PartialFunction (大括号内的一组case语句封装为函数) 匿名函数 高级函数 类型推断 闭包 柯里化 递归

偏函数PartialFunction  (大括号内的一组case语句封装为函数)

1 对符合某个条件的情况下,进行逻辑操作时 它只对会作用于指定类型的参数或指定范围值的参数实施计算,超出范围的值会忽略
2 将包在大括号内的一组case语句封装为函数
3 偏函数继承一个特质 PartialFunction

偏函数简化形式

函数作为一个变量传入到了另一个函数中,那么该作为参数的函数的类型是:function1,即:(参数类型) => 返回类型

object PartialFunTest02 {
  def main(args: Array[String]): Unit = {
    val list1 = List(1, 2, 3, 4, "hello")

    //使用偏函数
    //说明:如果是使用偏函数,则不能使用map,应该使用collect
    //说明一下偏函数的执行流程
    //1. 遍历list所有元素
    //2. 然后调用 val element = if(partialFun-isDefinedAt(list单个元素)) {partialFun-apply(list单个元素) }
    //3. 每得到一个 element,放入到新的集合,最后返回
    val list2 = list1.collect(pFun)
    println(list2 )  //List(2, 3, 4, 5)

    val list3 = list1.collect(pFun2)
    println(list3 ) //List(2, 3, 4, 5)


    //  方式三  直接接  list.collect { case 1  case 2 }
    val list4 = list1.collect {
      case i: Int => i + 1
      case j: Double => (j * 2).toInt
    }
    println( list3 )
  }

  // 方式1 正常定义方法 override 重写 def isDefinedAt    重写 def apply
  //1. PartialFunction[Any,Int] 表示偏函数接收的参数类型是Any,返回类型是Int
  //2. isDefinedAt(x: Any) 如果返回true ,就会去调用 apply 构建对象实例,如果是false,过滤
  //3. apply 构造器 ,对传入的值 + 1,并返回(新的集合)
  val pFun=  new PartialFunction[Any, Int] {
    override def isDefinedAt(x: Any): Boolean = x.isInstanceOf[Int]
    override def apply(v1: Any): Int = v1.asInstanceOf[Int] + 1
  }

  // 方式2 简写 定义方法

  def pFun2: PartialFunction[Any, Int] ={
    //  case i: int ( def isDefinedAt(x: Any): Boolean = x.isInstanceOf[Int])
    // => i + 1 (def apply(v1: Any): Int = v1.asInstanceOf[Int] + 1 )
    case i : Int => i +1
    case j: Double => (j * 2).toInt
  }
}


匿名函数

函数作为一个变量传入到了另一个函数中,
那么该作为参数的函数的类型是:function1,即:(参数类型) => 返回类型

object AnonyFunParameter {
  def main(args: Array[String]): Unit = {
    //   函数作为参数 传入
    //def map[B, That](f: A => B) 的声明中的 f: A => B 一个函数
    //map(plus(_)) 中的plus(_) 就是将plus这个函数当做一个参数传给了map,_这里代表从集合中遍历出来的一个元素。
    //plus(_) 这里也可以写成 plus 表示对 Array(1,2,3,4) 遍历,将每次遍历的元素传给plus的 x
    //进行 x * 2  运算后,返回新的Int ,并加入到新的集合 result1 中

    val result1 = Array(1, 2, 3, 4).map(plus(_))
    println(result1.mkString("_")) //2_4_6_8
    //1. 在scala中,函数也是有类型,比如plus就是 <function1>
//    println("puls的函数类型function1" + (plus _))

    // 匿名函数
    //1. 不需要写 def 函数名
    //2. 不需要写返回类型,使用类型推导
    //3. =  变成  =>
    //4. 如果有多行,则使用{} 包括
    var triple =  (x: Int) => x * 3

    println(triple(3)) //9

    val arry2 = Array(1, 2, 3).map((x: Int) => x * 4)
    println(arry2.mkString(","))  //4,8,12

  }

  //   函数作为参数 传入
  def plus(x: Int) =  x *2
}


高阶函数

能够接收函数作为参数的函数,也可以返回一个函数,叫做高阶函数 (higher-order function)

object HighorderTest2 {
  def main(args: Array[String]): Unit = {
    val ho1 =horder2 (sum, mod, 5.0)
//    println(ho1 )

    // result1 就是  (y: Int) => 100 - y
    val result1 = minusxy(100)
    println( "result1类型:" + result1)
    println(result1(50 ))   //100 -50

    //也可以一步到位的调用  柯里化
    val result2 = minusxy(10)(5)
//    println(result2)

  }

  // 接收一个函数

  def sum(d: Double): Double = {
    d + d}

  def mod(d:Double): Int = {
    d.toInt % 2}
  //高阶函数  能够接受函数作为参数,返回一个函数 的函数,叫做高阶函数 (higher-order function)
  // horder2 接受 f1, f2 函数

  def horder2( f1: Double => Double, f2: Double => Int, n1: Double) ={
    f1(f2(n1))
  }

  // 返回一个函数
  //1. minusxy是高阶函数,因为它返回匿名函数
  //2. 返回的匿名函数 (y: Int) => x - y
  //3. 返回的匿名函数可以使用变量接收
  def minusxy(x: Int) = {
    (y: Int) => x - y //返回一个 匿名函数;闭包 x 是从外部传进来的,(y: Int) => x - y; x与这个匿名函数形成一个整体
  }
}


类型推断

当遍历list时,参数类型是可以推断出来的,可省略数据类型
当传入的函数,只有单个参数时,可以省去括号 
如果变量只在=>右边只出现一次,可以用_来代替  同时=>左边都省略

object ParameterInferTest {
  def main(args: Array[String]): Unit = {
    // 类型推断 &  简化
//    当遍历list时,参数类型是可以推断出来的,可省略数据类型
//    当传入的函数,只有单个参数时,可以省去括号
//    如果变量只在=>右边只出现一次,可以用_来代替  同时=>左边都省略
    val list = List(1, 2, 3, 4)
    println(list.map((x:Int)=>x + 1))
    println(list.map((x)=>x + 1))  //list 里面元素都是int x 肯定也是 int,省略类型
    println(list.map(x=>x + 1))    // 一个参数是 () 省略
    println(list.map( _ + 1))      // 右边只出现一次,可以用_来代替, => 省略
  }
}


闭包  closure  一个函数和与其相关的引用环境组合的一个整体(类似对象方法和属性关系)
def minusxy(x: Int) = (y: Int) => x - y

object ClosureTest {
  def main(args: Array[String]): Unit = {
    val func_closure = makeend(".mp4")

    println(func_closure("alex")) //alex.mp4
    println(func_closure("bob.mp4")) //bob.mp4

    // 柯里化
    val str = makeend(".mp3")("sumi")
    println(str)
  }

  //  闭包 一个函数和与其相关的引用环境组合的一个整体(类似对象方法和属性关系)
  //  下面 一个匿名函数 (filename) =>{ } 引用一个参数 (endpoint) 形成一个整体
  def makeend( endpoint: String) = {
    (filename: String ) => {
      if (filename.endsWith(endpoint))
        { filename}
      else
        {filename + endpoint}
    }}
}
}


函数柯里化(curry)

函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化 ,证明函数只需要一个参数而已。

object CurryTest1 {
  def main(args: Array[String]): Unit = {
    println(mul1(2, 5))
    println(mul2(2)(5))
    println(mul3(2)(5))

    // 柯里化例2
    //    str1.checkeq("sumi")((s1: String, s2: String) => s1.equals(s2))
    //    str1.checkeq("sumi")((s1, s2) => s1.equals(s2))
    //    str1.checkeq("sumi")( _.equals(_))
    val str1 = "hello"
    println(str1.checkeq("alex")(eq _))  //false
    println(str1.checkeq("bob")(_ equals (_))) //false
    println(str1.checkeq("HELLO")(_ equals (_))) //true

  }
  // 常规比较, s1, s2 传入, 返回Boolean
  def eq(s1: String, s2: String) : Boolean ={s1.equals(s2)}

  // 隐式类 如果 一个s 是字符串 传入,就可以 使用 checkeq方法
  implicit class TestEQ (s: String ){
    def checkeq (ss: String)(f: (String, String)=> Boolean): Boolean ={
      f(s.toLowerCase, ss.toLowerCase)
    }
  }

  //柯里化 函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数

  // 柯里化 1 常规方式
  def mul1 (x:Int, y:Int) = x * y

  // 柯里化 2  闭包方式
  def mul2 (x:Int) = (y: Int) => x * y

  // 柯里化 3 柯里化
  def mul3(x:Int)(y:Int) = x * y
}

控制抽象是这样的函数,满足如下条件
参数是函数
函数参数没有输入值也没有返回值

object AbstractControlTest1 {
  def main(args: Array[String]): Unit = {

    //控制抽象是这样的函数,满足如下条件
    //参数是函数
    //函数参数没有输入值也没有返回值


    //说明
    //1 函数名为 mywhile也是个控制抽象 , 实现了类似while循环的效果
    //2. condition: => Boolean 是 没有输入值,返回Boolean类型函数
    //3. block: => Unit 没有输入值,也没有返回值的函数 ,调用时候传入代码块(就是匿名函数)
    def mywhile(condition: => Boolean)(block: => Unit): Unit ={
      if(!condition) {
        block // x= 9 ,x = 8 x =7 ....
        mywhile(condition)(block)
      }}
    var x =5
    // mywhile()()
    mywhile(x==0)({x -=1; println(x)})

    // 简化
    mywhile(x==0){x -=1; println(x)}
  }
}


递归

object recursiveTest {
  def main(args: Array[String]): Unit = {
    val now: Date = new Date()
    val dateFormat: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    val date = dateFormat.format(now)
    println("date=" + date) //输出时间

    var num = BigInt(1)
    var sum = BigInt(0)
    var res = mx(num,sum)
    println("res=" + res)

    val now2: Date = new Date()
    val date2 = dateFormat.format(now2)
    println("date2=" + date2) //输出时间
  }

  def mx(num: BigInt, sum: BigInt): BigInt = {
    if (num <= 99999999l) return mx(num + 1, sum + num)
    else return sum
  }

  //求最大值
  def max(xs: List[Int]): Int = {
    if (xs.isEmpty)
      throw new java.util.NoSuchElementException
    if (xs.size == 1)
      xs.head
    else if (xs.head > max(xs.tail)) xs.head else max(xs.tail)
  }

  // 翻转
  def reverse(xs: String): String =
    if (xs.length == 1) xs else reverse(xs.tail) + xs.head
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。