《Scala函数式编程》第三章习题解答

3.1 下面的匹配表达式结果是什么?

val x = 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

package com.lyzz.test.scala

object test_03 {

  def main(args: Array[String]): Unit = {
     val x = List(1,2,3,4,5) match {
     case x::(2 ::(4::_)) => x
     case Nil => 42
     case x::(y::(3::(4::_))) => x + y
     case h::t => h + sum(t)
     case _ => 101
   }
    println(x)
  }

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

结果是 3

3.2 实现tail函数,删除一个List的第一个元素。注意这个函数的时间开销是常量级的。 如果列表是Nil,在实现的时候会有什么不同的选择?我们在下一章再回顾这个问题。

package com.lyzz.test.scala

object test_03 {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4,5)
    val list1 = List()
    println(tail(list))
    println(list1)
  }

  def tail[A] (l: List[A]): List[A] = l match {
    case Nil => Nil
    case _::t => t
  }
}

输出结果

List(2, 3, 4, 5)
List()

3.3
使用相同的思路,实现函数setHead用一个不同的值替代列表中的第一个元素。

package com.lyzz.test.scala
object tese_03 {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4,5)
    val list1 = List()
    println(setHead(list,20))
    println(setHead(list1,"Alex"))

  }
  def setHead[A] (y: List[A],x: A): List[A] = y match {
    case Nil => x +:Nil
    case _::t => x::t
  }

结果:

List(20, 2, 3, 4, 5)
List(Alex)

3.4 把tail泛化为drop函数,用于从列表中刪除前n个元素。注意,这个函数的时间开销只需要与drop的元素个数成正比一不需 要复制整个列表。

package com.lyzz.test.scala

object test_03 {

  def main(args: Array[String]): Unit = {

    val ints: List[Int] = List(1,2,3,4,5,6,7,8,9)
    println( drop(ints,4))
  }
// 递归调用删除
  def drop[A] (L: List[A],n: Int): List[A] ={
    if(n == 0) L
    else L match {
      case Nil => Nil
      case _::t => drop(t,n-1)
    }
  }
}

结果

List(5, 6, 7, 8, 9)

3.5
实现dropWhile函数,删除列表中前缀全部符合判定的元素。
def dropWhile[A] (l: List[A], f: A => Boolean) : List [A]

package com.lyzz.test.scala

object test_03 {

  def main(args: Array[String]): Unit = {

    val ints: List[Int] = List(1,3,5,7,8,9)
    val f = (x: Int) =>{x%2==1}
    println(dropWhile(ints,f))
    println(dropWhile_curry(ints)(f))
  }

  def  dropWhile[A](l: List[A], f: A => Boolean): List[A] = l match {
    case h::t if(f(h)) =>dropWhile(t,f)
    case _ => l
}

  //改进:currying
  def dropWhile_curry[A](l: List[A])(f: A => Boolean): List[A] = l match {
    case h::t if(f(h)) => dropWhile_curry(t)(f)
    case _ => l
  }
}

3.6 不是所有的实现都这么令人满意,实现一个init函数,返回一个列表,它包含原列表中除了最后一个元素之外的所有元素。比如,传入List(1,2,3,4)给init函数会返回List(1,2,3),为什么这个函数不能实现同tail一样的常量级时间开销?
def init[A] (l: List[A]): List[A]

package com.lyzz.test.scala

object test_03 {

  def main(args: Array[String]): Unit = {
    val ints: List[Int] = List(1,3,5,7,8,9)
    println(init(ints))
  }
  
  def init[A](l: List[A]): List[A] = l match {
    case Nil => Nil
    case _::Nil => Nil
    case h::t => h::init(t)
  }
}

结果:

List(1, 3, 5, 7, 8)

3.8
当你对foldRight传人Nil和Cons时,看看会发生什么?例如: foldRight (
List(1,2,3,4),Nil:List[Int]) (Cons(_ ,_ ) )。 "说到foldRight和List
数据结构之间的关系,你有什么想法?

package com.lyzz.test.scala
object test_03 {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4,5)
    println(list.foldRight(Nil:List[Int])(_::_))
   }
 }

结果:

List(1, 2, 3, 4, 5)
...刚开始学scala,还不是很了解,等以后了解再回来解答这题

3.9 使用foldRight计算List 的长度。
def length[A] (as: List[A]) : Int

package com.lyzz.test.scala

object test03 {

  def main(args: Array[String]): Unit = {
    val ints: List[Int] = List(1,1,1,1,5,4)
    println(length(ints))
  }
  
  def foldRight[A,B](as: List[A],z:B)(f:(A,B)=>B):B =
    as match {
      case Nil => z
      case x::xs =>f(x,foldRight(xs,z)(f)) //遍历完从最后一位开始操作
    }
    
  def length[A](as: List[A]):Int =foldRight(as,0)((_,xs)=>xs+1)
  
}

结果

6

3.10 我们实现的foldRight不是尾递归,如果List很大可能会发生StackOverflowError(我们称之为非栈安全的)。说服自己接收这种情况,然后用尾递归方式写另一个通用的列递归函数foldLeft。签名如下:
def foldLeft[A,B] (as: List[A], z: B) (f: (B, A) => B): B

package com.lyzz.test.scala

object test03 {

  def main(args: Array[String]): Unit = {
    val ints: List[Int] = List(1,1,1,1,5,4)
    println(foldLeft(ints,0)(_ + _))
  }
  
  @annotation.tailrec
  def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
    as match {
      case Nil => z
      case x::xs =>foldLeft(xs,f(z,x))(f) //直接从头开始f操作
    }
    
}
答案:13

3.11 写一下sum、product函数,和一个用foldLeft计算列表长度的函数。

package com.lyzz.test.scala

object test03 {

  def main(args: Array[String]): Unit = {
    val ints: List[Int] = List(1,1,1,1,5,4)
    println(length(ints))
    println(sum(ints))
    println(product(ints))
  }
  
 @annotation.tailrec
  def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
    as match {
      case Nil => z
      case x::xs =>foldLeft(xs,f(z,x))(f) //直接从头开始f操作
    }
    
  def length[A](as: List[A]): Int = foldLeft(as,0)((xs,_)=>xs+1)

  def product(l: List[Int]): Int =
    l match {
      case Nil => 1
      case x::t => x*product(t)

    }

  def sum(l: List[Int] ): Int =
    l match{
      case  Nil => 0
      case x::t => x+sum(t)
    }

}

3.12
写一个对原列表元素颠倒顺序的函数(List(1,2,3) 返回List(3,2,1) ),看看是否可用一种折叠( fold )实现。

package com.lyzz.test.scala

object test03 {

  def main(args: Array[String]): Unit = {
    val ints: List[Int] = List(1,1,1,1,5,4)
      println(reverse(ints))
  }
  
 @annotation.tailrec
  def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
    as match {
      case Nil => z
      case x::xs =>foldLeft(xs,f(z,x))(f) //直接从头开始f操作
    }
    
  def reverse[T](list: List[T]): List[T] = foldLeft(list:List[T],Nil:List[T])((res,cur)=>cur::res)
  
}

✧-练习3,13
难:你是否能根据foldRight来写-一个foldLeft ?有没有其他变通方式?通过foldLeft来实现foldRight很有用,因为这会让我们以尾递归的方式实现。意味着不管列表有多大都不会产生栈溢出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值