Scala_函数式编程高级_递归

举报
alexsully 发表于 2021/04/23 18:23:11 2021/04/23
【摘要】 偏函数PartialFunction  (将包在大括号内的一组case语句封装为函数)对符合某个条件的情况下,进行逻辑操作时 它只对会作用于指定类型的参数或指定范围值的参数实施计算,超出范围的值会忽略偏函数简化形式函数作为一个变量传入到了另一个函数中,那么该作为参数的函数的类型是:function1,即:(参数类型) => 返回类型object PartialFunTest02 { def...

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

对符合某个条件的情况下,进行逻辑操作时 它只对会作用于指定类型的参数或指定范围值的参数实施计算,超出范围的值会忽略

偏函数简化形式

函数作为一个变量传入到了另一个函数中,那么该作为参数的函数的类型是: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 => i +1
    case j: Double => (j * 2).toInt
  }
}

匿名函数

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. 不需要写 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 )

    val result = minusxy(10)(5)
    println(result)
    
  }

  // 接收一个函数

  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
  }

  //  闭包 一个函数和与其相关的引用环境组合的一个整体(类似对象方法和属性关系)
  //  下面 一个匿名函数 (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
    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)}


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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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