1. 定义函数式数据结构
// 定义一个临时接口,为防止被继承使用sealed进行修饰
sealed trait testList[+A]
// 定义原子实例,使得递归后可以在原子实例上进行收敛、返回结果
case object Nil extends testList[Nothing] // Nothing是代表空值的类型
// 定义组合类型,使用样例类继承接口,用于迭代生成可被拆分的组合类型
case class testCons[+A](head: A , tail:testList[A]) extends testList[A]
// 定义临时接口的实例类,对原子实例和组合类型进行递归操作
object testList{
def sum(ints: testList[Int]):Int = ints match{
case Nil => 0
case testCons(x, xs) => x + sum(xs)
}
def product(ds: testList[Double]):Double = ds match{
case Nil => 1.0
// 短路逻辑:若发现有0,则直接结束递归
case testCons(0.0, _ ) => 0.0
case testCons(x, xs) => x * product(xs)
}
// 列表解析:_*只能在参数列表中使用,使得Seq[A]向下兼容A类型
def apply[A](as:A*):testList[A] = if(as.isEmpty) Nil else testCons(as.head, apply(as.tail:_*))
}
2. 模式匹配
// 变量模式_,表示匹配任何表达式,也可以用x或y等任意变量名称代替
testList(1,2,3) match {case _ => 1}
// 数据构造器模式,对类型进行匹配
// 通常结合变量模式_ 捕获目标的子表达式,参数个数和参数类型都必须满足要求,不能列表解析(:_*)
testList(1,2,3) match {case testCons(h, _) => h}
// 数据构造器模式,另一种形式
testList(1,2,3) match {case testCons(_, h) => h}
// 数据构造器模式,支持变长参数的匹配
List(1,2,3) match {case List(h, _*) => h}
// 数据构造器模式,错误的变长参数的匹配,_*必需放在参数列表的最后,_*为语法糖,固定搭配,不能演变为a*、b*等
List(1,2,3) match {case List(_*, h) => h}
// 数值模式,对值进行匹配
List(1,2,3) match{ case List(1,2,3) => 1}
// 若类型与数值均无法匹配,报错MatchError
List(1,2,3) match{ case Nil => 1}
3. 函数式数据结构的数据共享
理想情况下,由于函数式编程不存在副作用,可以做到:一份数据、多处引用、到处使用
4. 基于list的递归并泛化为高阶函数
<泛化>是指提取共性,降低代码重复
泛化前,观察1中定义的两个功能高度相似的sum、product的区别:
a. 参数类型差异:sum接受类型List[Int],product接受类型List[Double],泛化后应当可以处理类型List[A]
b. 递归边界条件差异:sum中List为Nil时返回0,product中List为Nil时返回1.0,泛化后应当可以指定List为空时的返回值
c. 计算方法差异:sum中计算方法为+,product中计算方法为*,泛化后应当可以指定不同的计算方法
泛化时,构思与伪代码:
a. 参数类型泛化:接受参数类型List[A]
b. 递归边界条件泛化:指定递归边界条件,兼容Int和Double类型,用B表示
c. 计算方法泛化:指定计算方法,f:(A,B) => B
泛化时,涉及的代码特性
a. 指定泛型:参数类型泛化、递归边界条件泛化、计算方法泛化时均涉及泛型,需要在方法名后标记泛型foldRight[A, B]
b. 柯里化:参数列表分为两部分,变量与函数,可以在进入sum、product方法内部后再指定函数
def foldRight[A, B](as: List[A], z: B)(f:(A, B) => B): B =
as match {
case Nil => z
case testCons(x, xs) => f(x, foldRight(xs, z)(f))
}
泛化后,新的sum、product方法
def sum2(ns:List[Int]) = foldRight(ns, 0)((x, y) => x + y)
def product2(ns:List[Double]) = foldRight(ns, 1.0)((x, y) => x * y) // (x, y) => (x * y)等价于(_ * _)