Scala函数式编程第三章答案与疑难解答

网上相关的scala资料较少,本文为博主搜查网上大多数资料之后的总结性博文。对于初次学习Scala(重点是初次看Scala函数式编程没有基础的道友),一些相关的疑难解答与第三章答案 。

/*
* Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
* 与接口不同的是,它还可以定义属性和方法的实现。一般情况下Scala的类
* 只能够继承单一父类,但是如果是 Trait(特征) 的话就可以继承多个,
* 从结果来看就是实现了多重继承。
* Scala 的类定义可以有参数,称为类参数,类参数在整个类中都可以访问。
* */

/*
* Scala 单例对象(object)
*在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,
* 那就是使用关键字 object。Scala 中使用单例模式时,除了定义的类之外,还要定义
* 一个同名的 object 对象,它和类的区别是,object对象不能带参数。当单例对象
* 与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。
* 你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:
* companion class。类和它的伴生对象可以互相访问其私有成员。
* */


/*
* sealed关键字两个主要作用:
* 1、修饰的trail,class只能在当前文件里被继承。
* 2、用sealed修饰这样做的目的是告诉scala编译器在检查模式匹配的时候,
*   让Scala知道所有情况,scala就能在编译的时候检查,看看是否没有漏掉什么case,
*   减少编程错误(用在多态上,存在多孩子类型)
* */

/*
* case class 和普通的class大致相同,不过主要有四大区别,定义上只需要class前加case:
* 1、提供factory method来方便构造object.
* 2、class parameter隐含val prefix
* 3、自带toString,hashCode,equals实现
* 4、默认是可以序列化的,也就是实现了Serializable
* case class 最大的就是方便做pattern matching
* */

/*
*为什么case class 最大的就是方便做pattern matching?
* case class的作用:
* 1、内置了apply函数,构造时无需加new,而class需要定义其伴生对象,
*   通过object Calculator 中的apply函数才可以直接通过类名加括号和
*   参数的形式构造新实例。
*2、而且构造器的变量名无需声明val(构造参数默认为val)即为成员常量,
* 可以在类定义外访问hp30b.brand ( hp30b.brand//brand无需声明val )
*   (如果构造参数申明为var则默认实现了getter和setter方法)
*3、声明为case class或者case object才可以进行模式匹配,
*   class不可以,不仅可以是通过类名匹配,还可以同一类名
*   但通过不同的参数进行识别匹配。
* */

 

sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]

object List {

  def sum(ints: List[Int]): Int = ints match {
    case Nil => 0
    case Cons(x, xs) => x + sum(xs)
  }

  def product(ds: List[Double]): Double = ds match {
    case Nil => 1.0
    case Cons(0.0, _) => 0.0
    case Cons(x, xs) => x * product(xs)
  }

  def apply[A](as: A*): List[A] =
    if (as.isEmpty) Nil
    else Cons(as.head, apply(as.tail: _*))

  val x: Int = List(1,2,3,4,5) match {
    case Cons(x, Cons(2, Cons(4, _))) => x
    case Nil => 42
    case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y
    case Cons(h, t) => h + sum(t)
    case _ => 101
  }

  // 3.2实现tail删除一个List 的第一个元素
  def tail[A](l: List[A]): List[A] = l match {
    case Nil => sys.error("tail of empty list")
      // _ 是类似一正则表达式,匹配任何表达式
    case Cons(h, t) => t
  }

  //3.3使用相同的思路,实现用一个不同的之代替第一个值。
  def setHead[A](l: List[A], h: A): List[A] = l match {
    case Nil => sys.error("setHead on empty list")
    case Cons(_, t) => Cons(h, t)
  }

  //3.4 把tail泛化为drop函数,用于从列表删除前n个元素。

  def drop[A](l: List[A], n: Int): List[A] = {
    if(n <= 0) l
    else l match {
      case Nil => Nil
      case Cons(_, t) => drop(t, n - 1)
    }
  }

  //3.5 实现dropwhile函数,删除列表中前缀全部符合判定的元素。

  /*def dropWhile[A](l: List[A], f: A => Boolean): List[A] = l match {
    case Cons(h, t) if(f(h)) => dropWhile(t, f)
    case _ => l
  }*/
  // 科里化,充分利用类型推导
  def dropWhile[A](l: List[A])(f: A => Boolean): List[A] =
    l match {
      case Cons(h, t) if(f(h)) => dropWhile(t)(f)
      case _ => l
    }


  // 利用数据共享的特性将一个列表的所有元素加到另一个列表的后面
  def append[A](a1: List[A], a2: List[A]): List[A] = a1 match {
    case Nil => a2
    case Cons(h, t) => Cons(h, append(t, a2))
  }


  //3.6去除尾部元素
  def init[A](l: List[A]): List[A] = l match {
    case Nil => Nil
    case Cons(_, Nil) => Nil
    case Cons(h, t) => Cons(h, init(t))
  }


  //加速
  def init[A](cur: List[A]): List[A] = {
    import collection.mutable.ListBuffer
    val buf = new ListBuffer[A]
    @annotation.tailrec
    def go(l: List[A]): List[A] = l match {
      case Nil => sys.error("init into empty list")
      case Cons(_, Nil) => List(buf.toList: _*)
      case Cons(h, t) => buf += h; go(t)
    }
    go(cur)
  }


  //3.2右折叠简单应用
  def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B =
    as match {
      case Nil => z
      case Cons(h, t) => f(h, foldRight(t, z)(f))
    }
  def sum2(ns: List[Int]): Int =
    foldRight(ns, 0)((x,y) => x + y)

  def product2(ns: List[Double]): Double =
    foldRight(ns, 1.0)(_ * _)


  // 3.9 使用flodRight 计算List长度
  def length[A](as: List[A]): Int = {
    foldRight(as, 0)((_, acc) => acc + 1)
  }

  /*
  * 我们所说的尾递归调用是指一个递归调用之后不做其他事情,只返回这个调用结果
  * 如go(n - 1, n * acc)
  * */
  //3.10用尾递归调用实现foldLeft
  def foldLeft[A, B](as: List[A], z: B)(f: (A, B) => B): B = as match {
    case Nil => z
    case Cons(h, t) => foldLeft(t, f(h, z))(f)
  }

  //3.11写一下sum,product函数,和一个用flodLeft计算列表长度
  def sum3(as: List[Int]): Int = {
    foldLeft(as, 0)(_ + _)
  }
  def product3(as: List[Double]): Double = {
    foldLeft(as, 1.0)(_ * _)
  }
  def length2[A](l: List[A]): Int = foldLeft(l, 0)((h, acc) => acc + 1)

  // 3.12用折叠实现元素颠倒
  def reverse[A](l: List[A]): List[A] = {
    foldLeft(l, List[A]())((h, acc) => Cons(h, acc) )
  }

  // 3.13 有几种没看懂暂时放下

  def foldRightViaFoldLeft[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
    foldLeft(reverse(l), z)(f)
  }

  //3.14 根据foldLeft或foldRight实现append
  def appendViaFoldRight[A](l: List[A], r: List[A]): List[A] = {
    foldRight(l, r)(Cons(_, _))
  }

  // 3.15连接一组列表
  def concat[A](l: List[List[A]]): List[A] = {
    foldRight(l, Nil: List[A])(append)
  }

  // 3.16 写一个函数,用来转换一个列表,对每一个元素加一
  def add1(l: List[Int]): List[Int] = {
    foldRight(l, Nil: List[Int])((h, t) => Cons(h + 1, t))
  }

  // 3.17写一个函数,将List[Double]中的每一个值转化为String
  def doubleToString(l: List[Double]): List[String] = {
    foldRight(l, Nil: List[String])((h, t) => Cons(h.toString, t))
  }

  // 3.18写一个泛化的map函数
  def map[A, B](as: List[A])(f: A => B): List[B] = {
    foldRight(as, Nil: List[B])((h, t) => Cons(f(h), t))
  }

  // 3.19 写一个filter函数,从列表中删除所有不满足的元素,并用他删除奇数元素
  def filter[A](as: List[A])(f: A => Boolean): List[A] = {
    foldRight(as, Nil: List[A])((h, t) => if(f(h)) Cons(h, t) else t)
  }

  // 3.20写一个flatMap函数,他跟map函数有些像。这个函数会把函数f返回的结果塞到flatmap
  // 最终返回。
  /*
  * 例如: flatMap(List(1, 2, 3))(i => List(i, i)) 结果是List(1,1,2,2,3,3)
  * */
  def flatMap[A,B](l: List[A])(f: A => List[B]): List[B] =
    concat(map(l)(f))
  // 3.21 用flatMap实现filter
  def filterViaFlatMap[A, B](as: List[A])(f: A => Boolean): List[A] = {
    flatMap(as)(h => if(f(h)) List(h) else Nil)
  }

  // 3.22 对应位置相加
  def addPairwise(l: List[Int], r: List[Int]): List[Int] = (l, r) match {
    case (Nil, _) => Nil
    case (_, Nil) => Nil
    case (Cons(h1,t1), Cons(h2,t2)) => Cons(h1+h2, addPairwise(t1,t2))
  }

  // 3.23 泛化
  def zipWith[A](l: List[A], r: List[A])(f: (A, A) => A): List[A] = (l, r) match {
    case (Nil, _) => Nil
    case (_, Nil) => Nil
    case (Cons(h1,t1), Cons(h2,t2)) => Cons(f(h1, h2), zipWith(t1,t2)(f))
  }

  // 3.24 要再看一下,字符串匹配
  @annotation.tailrec
  def startsWith[A](l: List[A], prefix: List[A]): Boolean = (l,prefix) match {
    case (_,Nil) => true
    case (Cons(h,t),Cons(h2,t2)) if h == h2 => startsWith(t, t2)
    case _ => false
  }

  @annotation.tailrec
  def hasSubsequence[A](sup: List[A], sub: List[A]): Boolean = sup match {
    case Nil => sub == Nil
    case _ if startsWith(sup, sub) => true
    case Cons(h,t) => hasSubsequence(t, sub)
  }
}
sealed trait Tree[+A]
case class Leaf[A](values: A) extends Tree[A]
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]

object Tree {

  // 3.25 写一个size函数,统计一棵树的节点数
  def size[A](t: Tree[A]): Int = t match {
    case Leaf(_) => 1
    case Branch(left, right) => 1 + size(left) + size(right)
  }

  // 3.26下一个maxinum函数,返回这棵树最大元素
  def maxinum(t: Tree[Int]): Int = t match {
    case Leaf(t) => t
    case Branch(left, right) => maxinum(left) max maxinum(right)
  }

  // 3.27写一个depth函数,返回一棵树中从根节点到任何节点最深
  def depth[A](t: Tree[A]): Int = t match {
    case Leaf(_) => 0
    case Branch(left, right) => 1 + (depth(left) max depth(right))
  }

  // 3.28写一个函数,类似于List中同名函数,接收一个函数,对书中每一个元素进行修改

  def map[A, B](t: Tree[A])(f: A => B): Tree[B] = t match {
    case Leaf(a) => Leaf(f(a))
    case Branch(left, right) => Branch(map(left)(f), map(right)(f))
  }

  // 3.29 对上述函数进行泛化
  def fold[A, B](t: Tree[A])(f: A => B)(g: (B, B) => B): B = t match {
    case Leaf(a) => f(a)
    case Branch(left, right) => g(fold(left)(f)(g), fold(right)(f)(g))
  }

  //对size的泛化
  def sizeViaFold[A](t: Tree[A]): Int =
    fold(t)(a => 1)(1 + _ + _)

  //对maxinum的泛化
  def maximumViaFold(t: Tree[Int]): Int =
    fold(t)(a => a)(_ max _)

  // 对depth的泛化
  def depthViaFold[A](t: Tree[A]): Int =
    fold(t)(a => 0)((d1,d2) => 1 + (d1 max d2))

  // 对map的泛化
  def mapViaFold[A,B](t: Tree[A])(f: A => B): Tree[B] =
    fold(t)(a => Leaf(f(a)): Tree[B])(Branch(_,_))
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值