Coursera公开课Functional Programming Principles in Scala习题解答:Week 二

Coursera公开课Functional Programming Principles in Scala习题解答:Week 2

引言

OK.时间很快又过去了一周,第一周有五一假期所以感觉时间绰绰有余,这周中间没有假期只能靠晚上加周末的时间来消化,其实还是有点紧张呢!后来发现每堂课的视频还有对应的课件(Slide)、字幕(subtitles)可以下载,这样下载视频学习和在线学习就只差课程中间的Exercise了

Week 2主要讲函数,函数在Scala里是first-class citizen,可以在任意域内出现,这门课其实也是在借Scala来讲函数式编程原理。好了,不多说,进入习题解析。

 

这周的作业主要是使用函数来表示一个集合,可以通过传递给函数一个整型值得到布尔值来验证此整型值是否属于此集合。好,说太绕了,下面是给出的一个栗子:

(x: Int) => x < 0


这是一个匿名函数,将一个传入的x映射为布尔值,从而判断x是否属于这个函数表示的集合。很明显,这个集合是负整数集。

题目就从这里开始,使用一个Int到Boolean的函数作为集合的表示,并给其赋了一个别名:

type Set = Int => Boolean


所以,在本此作业中定义的集合要以函数的形式给出。前面说到的函数是一等公民,当然可以作为返回值。对应的,判断一个值是否在给定集合内的方法如下:

def contains(s: Set, elem: Int): Boolean = s(elem)


可以看出contains函数传进一个Set和一个Int作为参数,前面提到Set是一个输入为Int类型的函数,所以将s应用到elem上,就得到一个Boolean类型的返回值。

 

Exercise 2.1 Basic Functions On Sets

练习2.1完成集合的一些简单操作的定义。

singletonSet

开始当然是定义一个集合啦~这个集合是个单例集合,其只能存放一个值,签名如下:

def singletonSet(elem: Int): Set

 

可以使用Int类型的参数来初始化这个函数,返回的是一个Set类型,也就是Int => Boolean的函数。我们已经知道集合中只包含elem这个元素,那么只需要判断一个元素是否等于elem就可以了。

代码自己写吧……

union, intersect and diff

上面我们定义了一个最简单的集合,接下来可以通过简单集合的不断组合生成新的集合。比较常用的三种操作是union、intersect和diff,其原型如下:

def union(s: Set, t: Set): Set
def intersect(s: Set, t: Set): Set
def diff(s: Set, t: Set): Set

以上三个操作均是通过组合两个Set得到一个新的Set,分别表示两个集合的并集、交集和差集,这些概念都比较简单。

1.union就是在s中或者在t中的元素组成的集合,所以只需要判断一个元素是否在这两者其一即可

2.intersect就是在s中且在t中的元素组成的集合,所以需要判断一个元素是否同时在这两者中

3.diff就是在s中且不在t中的元素组成的集合,需要判断一个元素在s且不在t中

 

代码,自己写。

filter

接下来是要实现一个filter函数,即选取集合s中符合断言p的元素,这些元素组成的同样是一个集合。filter的原型如下:

def filter(s: Set, p: Int => Boolean): Set

这个其实比较简单了,实质上是intersect的变形,只不过intersect的第二个入参是filter第二个入参的别名罢了。

 

Exercise 2.2 Queries and Transformations on Sets

作业2.2是完成一些在Set上的操作。

forall

第一个函数给定一个断言,判断Set中的所有元素是否都满足这个断言。签名如下:

def forall(s: Set, p: Int => Boolean): Boolean

我们定义Set的方式决定了无法实际列举Set内的所有元素,只能判断给定元素是否属于这个Set,所以如果要完成这个功能,我们需要遍历所有的整型数。这是不现实的,所以将其限定在-1000到1000范围内。

对于以上的forall函数,题目给出了一个框架,只需要在框架内把相应的部分(即???部分)填写完毕即可:

def forall(s: Set, p: Int => Boolean): Boolean = {
 def iter(a: Int): Boolean = {
   if (???) ???
   else if (???) ???
   else iter(???)
 }
 iter(???)
}


可以看到forall内部定义了一个函数iter,并将一个iter的实例作为forall的返回值(注意,这里又强调了一次函数是一等公民的概念!)

那么根据上述提示,我们需要遍历-1000到1000内的整型,依次判断其是否符合断言p,当然前提条件是这个整型也属于集合s。p是一个Int映射到Boolean类型的函数,只需要将整型数传递给它,判断其返回值即可知道此整型数是否符合p。判断一个数是否属于集合s可以使用Exercise 2.1中定义的contains函数来实现。

Main.scala中还定义了一个上界:

  /**
   * The bounds for `forall` and `exists` are +/- 1000.
   */
  val bound = 1000


其实这个还是比较简单,只需要从-1000到1000,依次判断其中属于集合s的元素是否都符合断言p即可。如果有一个不符合上述条件,那么返回false;如果都符合,返回true。

请自行实现。

exists

第二个需要实现的函数为exists,即判断集合s中是否含有符合给定断言的元素,签名如下:

def exists(s: Set, p: Int => Boolean): Boolean


注意,题目要求exists需要通过调用forall来实现。这个场景好熟悉啊……这不就是高中课本里的题目:“抛N枚硬币所有面都朝上的概率”,和“抛N枚硬币有一次面朝下的概率”之间的关系是一样的么?

OK,分析一下。判断集合s中是否有符合给定断言的元素,即判断集合s中所有元素是否都不符合给定断言。

如果s中所有元素都不符合给定断言,那么返回false;否则返回true。

懂了吧?下一题。

map

最后一道题目是写一个map函数,将给定集合映射到另外一个集合,签名如下:

def map(s: Set, f: Int => Int): Set

其中第二个参数f是用来将原集合的元素映射到新集合的函数(一等公民!)

题目看起来简单,只是判断s中的元素经过f映射后,是否有和输入整型相等的即可。

这其中包含两个步骤:

1.s中是否有符合某个特定条件(断言)的元素

2.特定条件(断言)为经过f映射,等于输入参数

记得返回类型为Set,即Int => Boolean类型的函数(一等公民!)!

 

结语

总体来说,Scala有别于其他面向对象语言的一个最大的特点是其混合了很多函数式编程的概念和方法,这在使用Scala的过程中尤其要注意!Scala可以看做是O教(面向对象编程)和F教(函数式编程)的合体!

PS:此次附带的FunSetSuite.scala中只有很少一部分测试用例,还有一些是被打上了ignore标签,如果自己有兴趣,可以试着写一些单元测试,保证能够覆盖到一些特殊情况,这样就不至于反复在Coursera的服务器上提交不完美的答案了!

PPS:现在补上了作业题目的下载链接和题面(防止网页失效带来的不便,以离线网页的形式给出),方面以后看到的同学自己练习!

第二章题目下载地址:http://download.csdn.net/detail/doggie_wangtao/7343177

Coursera公开课Functional Programming Principles in Scala习题解答:Week 1 

声明:

本文为原创,禁止用于任何商业用途,转载请注明出处:http://blog.csdn.net/asongoficeandfire/article/details/25661661