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類型的返回值。
練習2.1完成集合的一些簡單操作的定義。
開始當然是定義一個集合啦~這個集合是個單例集合,其只能存放一個值,簽名如下:
def singletonSet(elem: Int): Set
可以使用Int類型的參數來初始化這個函數,返回的是一個Set類型,也就是Int => Boolean的函數。我們已經知道集合中只包含elem這個元素,那麼只需要判斷一個元素是否等於elem就可以了。
代碼自己寫吧……
上面我們定義了一個最簡單的集合,接下來可以通過簡單集合的不斷組合生成新的集合。比較常用的三種操作是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函數,即選取集合s中符合斷言p的元素,這些元素組成的同樣是一個集合。filter的原型如下:
def filter(s: Set, p: Int => Boolean): Set
這個其實比較簡單了,實質上是intersect的變形,只不過intersect的第二個入參是filter第二個入參的別名罷了。
作業2.2是完成一些在Set上的操作。
第一個函數給定一個斷言,判斷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,即判斷集合s中是否含有符合給定斷言的元素,簽名如下:
def exists(s: Set, p: Int => Boolean): Boolean
注意,題目要求exists需要通過調用forall來實現。這個場景好熟悉啊……這不就是高中課本裡的題目:“拋N枚硬幣所有面都朝上的概率”,和“拋N枚硬幣有一次面朝下的概率”之間的關系是一樣的麼?
OK,分析一下。判斷集合s中是否有符合給定斷言的元素,即判斷集合s中所有元素是否都不符合給定斷言。
如果s中所有元素都不符合給定斷言,那麼返回false;否則返回true。
懂了吧?下一題。
最後一道題目是寫一個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