第二章 函数式数据结构
一. 定义一个函数式的List
- 通常使用trait关键字引入一种数据类型
- sealed trait表示这个trait的所有实现都必须定义在这个文件里
- MyList有2种实现,空和非空。非空借口由初始的head元素和接下来的MyList结构的tail组成。Cons由constructer缩写
- MyList[A+]:类型正向型变,若Dog是Animal的子类,则List[Dog]是List[Animal]的子类
- Nil继承了MyList[Nothing],而Nothing是所有类型的子类型,所以List[Nothing]可以当成List[Int],List[Double]。
- 伴生对象是一个单例对象
- apply方法,使得MyList声名出来后,每个结构都是head和tail的MyList类型
sealed trait MyList[+A] // 泛型类型 case object Nil extends MyList[Nothing] // 空List类型 case class Cons[+A](head:A,tail:MyList[A]) extends MyList[A] //非空list,开头是一个点,尾部是另一个List object MyList{ def sum(ints:MyList[Int]):Int = ints match { // 利用模式匹配,对整数型list元素进行求和 case Nil => 0 // 控列表的累加值为0 case Cons(x,xs) => x + sum(xs) } def product(ds:MyList[Double]):Double = ds match { // 对list的值进行求积 case Nil => 1.0 case Cons(0.0,_) => 0.0 case Cons(x,xs) => x * product(xs) } def apply[A](as:A*):MyList[A] = // A* 是可变参数列表,多个类型为A的参数 if(as.isEmpty) Nil else Cons(as.head,apply(as.tail:_*)) }
二. 函数式数据结构中的数据共享
-
函数式数据结构是持久的,即已存在的引用不会因数据结构的操作而改变。即函数式编程下产生的数据结构是不可变的
-
函数式数据结构不可变,意味着对原先的数据结构增删一个元素会返回一个全新的结果,这个结果不用去复制一份数据,可以直接复用他。
-
函数式数据结构的操作是以
模式匹配
+递归
构成的/** * Created by lj on 17-2-22. */ object MyList{ // 获取tail部分 def tail[A](l:MyList[A]):MyList[A] = { l match { case Nil => sys.error("tail of empty list") case Cons(_,t) => t } } //修改第一个元素的值 def setHead[A](l:MyList[A],h:A):MyList[A] = { l match { case Nil => sys.error("head of empty list") case Cons(_,t) => Cons(h,t) } } // 删除前n个元素 def drop[A](l:MyList[A],n:Int):MyList[A] = { if (n<=0) l else l match { case Nil => Nil case Cons(_,t) => drop(t,n-1) } } // 删除前面符合条件的元素 def dropWhile[A](l:MyList[A],f:A=>Boolean) :MyList[A] = { l match { case Nil => Nil case Cons(h,t) if f(h) => dropWhile(t,f) } } // 将一个列表的元素加到另一个元素的后面 /** 该方法只做数据复制,直到第一个列表中没有元素可用。所以时间和内存开销只取决于l1的长度 * 若我们用两个数组实现相同的函数,则被迫要复制两个数组中的所有元素到一个数组中 */ def append[A] (l1:MyList[A],l2:MyList[A]) :MyList[A] ={ l1 match { case Nil => l2 case Cons(h,t) => Cons(h,append(t,l2)) //case Cons(h,t) => append(t,Cons(h,l2)) } } // 返回除最后一个元素外的所有元素 // 这个函数不能实现像tail一样的常亮级时间 def init[A](l:MyList[A]):MyList[A] = { l match { case Nil => sys.error("init of empty") case Cons(_,Nil) => Nil case Cons(h,t) => Cons(h,init(t)) } } // 用高阶函数重写sum和product(这两个函数的代码大量重复) def folderight[A,B](l:MyList[A],z:B)(f:(A,B)=>B):B = { l match { case Nil => z case Cons(x,xs) => f(x,folderight(xs,z)(f)) } } def sum2(l:MyList[Int]) = folderight(l,0)((x,y)=>x+y) def product2(l:MyList[Double]) = folderight(l,1.0)(_ * _) def length[A](l:MyList[A]) : Int ={ folderight(l,0)((_,acc) => acc+1) } // 用folderleft改进folderright,形成尾递归版的sum,product def foldleft[A,B](l:MyList[A],z:B)(f:(B,A)=>B):B = { l match{ case Nil => z case Cons(h,t) => foldleft(t,f(z,h))(f) } } def sum3(l:MyList[Int]) = foldleft(l,0)(_+_) def product3(l:MyList[Double]) = foldleft(l,1.0)(_*_) def length2[A](l:MyList[A]) = foldleft(l,0)((a,b)=>a+1) def reverse[A](l:MyList[A]) = foldleft(l,MyList[A]())((acc,h) => Cons(h,acc)) }