第二章 函数式数据结构

一. 定义一个函数式的List

  1. 通常使用trait关键字引入一种数据类型
  2. sealed trait表示这个trait的所有实现都必须定义在这个文件里
  3. MyList有2种实现,空和非空。非空借口由初始的head元素和接下来的MyList结构的tail组成。Cons由constructer缩写
  4. MyList[A+]:类型正向型变,若Dog是Animal的子类,则List[Dog]是List[Animal]的子类
  5. Nil继承了MyList[Nothing],而Nothing是所有类型的子类型,所以List[Nothing]可以当成List[Int],List[Double]。
  6. 伴生对象是一个单例对象
  7. 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:_*))
    }
    

二. 函数式数据结构中的数据共享

  1. 函数式数据结构是持久的,即已存在的引用不会因数据结构的操作而改变。即函数式编程下产生的数据结构是不可变的

  2. 函数式数据结构不可变,意味着对原先的数据结构增删一个元素会返回一个全新的结果,这个结果不用去复制一份数据,可以直接复用他。

  3. 函数式数据结构的操作是以模式匹配+递归构成的

    /**
      * 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))
    }
    
posted @ 2017-02-24 14:53  moon_lord  阅读(487)  评论(0编辑  收藏  举报