ZJU Lambda2017秋納筆試
先簡單介紹一下,ZJU Lambda是我這學期在浙大Google Camp社團辦的一個討論組,目的是聚集起浙大喜歡玩函數式的同學一起學習函數式相關知識。為了納新,我出了下面這套筆試題,難度我認為差不多就是《趣學指南》前8章的難度,尚未涉及Monad。考出來效果非常好,好幾個80+,90+,還有100的。出題人日常被吊打(1/1)。
本人才疏學淺,如果題目出現紕漏,還請各位知友多多指教。
第一部分
函數式編程基礎(共50分)1. 以下屬於函數式編程理念的是(5分)
A. 過早的優化是萬惡之源
B. PHP是最好的語言
C. 代碼即數據,函數是一等公民
D. 變數的類型可以在運行時變化
2. 代數數據類型(algebraic data type)是函數式編程中非常重要的概念,請定義Int列表:
data IntList =______。(5分)
3. 若將代數數據類型(algebraic data type)與自然數建立映射,定義一個類型對應的自然數即為其可能的取值個數(以下稱作大小)。例如data Bool = True | False,Bool有兩個可能的取值True和False,那麼Bool的大小就為2;data T = E | S Bool Bool,T的取值有E;S True True;S True False;S False True;S False False一共5種,所以T的大小為5。以下說法錯誤的是(10分)
A. data C=ConsA A | ConsB B,則C的大小為A的大小和B的大小相加
B. data C=Cons A B,則C的大小為A的大小和B的大小相乘
C. data C=Cons (A->B),則C的大小為A的大小和B的大小相乘
D. 存在加法單位元Void和乘法單位元()(在自然數運算中,0為加法單位元,1為乘法單位元)
4. 若兩個代數數據類型具有相同的「大小」,那麼這兩個代數數據類型之間一定存在一一對應關係,我們稱這樣的兩個類型同構(Isomorphism)。以下關於同構的說法錯誤的是(10分)
A. data Bool = True | False ,data Gender = Boy | Girl,Bool和Gender同構
B. data A = P | Q | R,data B = P | Q,A和B不同構,[A]和[B]也不同構([a]為a的列表)
C. 同構具有自反性(A與A同構),對稱性(若A與B同構,則B與A同構)與傳遞性(若A與B同構,B與C同構,則A與C同構)
D. ((A,B),C)與(A,B,C)同構
5. λ 演算是最小的通用程序設計語言。
(1) 用符號λ來定義函數。例如:λx.x+1定義了一個以x為變數的函數,它的返回值是x+1
λx. λy.x+y定義了一個以x為自變數的函數,返回值是一個函數,那個函數的功能是+x
(2) 兩項並置表示函數應用,例如 (λx.x+1) y表示把函數(λx.x+1)應用到y上
(3) λ演算的兩條規則:
alpha轉換:變換λ表達式中的變數名稱不改變函數本身。例: λx.x+1與λy.y+1等價
beta規約:函數應用時,用實際的參數替換λ符號後定義的參數。例:(λx.x+3/x) y經過beta規約後即為y+3/y
計算出下面的Lambda表達式的值,或指出其為無限循環(2+2+3+3=10分)
A. (λx.x+1) 5 =
B. (λf.λx.f (x+1)) (λy.2*y) 3 =
C. (λf.λx.f (f x)) (λy.y+2) 1 =
D. λf.(λx.f (x x)) (λx.f (x x)) g =
6. 在程序證明領域有一句話叫「類型即命題,程序即證明」,例如,某個函數的類型簽名為a->a,那麼它對應的命題為若a為真,則a為真。如果你能寫出一個類型簽名為a->a的函數,那麼你寫的程序就是這個命題的證明。下面關於程序證明的描述,錯誤的是(10分)
A. 你可以寫出一個a->a類型的通用函數,這表明,若a為真,則a為真
B. 你可以寫出一個Two a b->b類型的通用函數,這表明,若a且b為真,則b為真(Two的定義見2題)
C. 你不能寫出一個Either a b->a類型的通用函數,這表明,若a或b為真,則a不一定為真
D. 你不能寫出一個a->b->Two a b類型的通用函數,因為這個函數的類型簽名沒有對應的邏輯命題
第二部分 Haskell語言基礎(共50分)
1. 下面關於Haskell語言的說法,錯誤的是(5分)
A. 函數可以作為參數傳遞
B. []列表類型可以做到常數時間隨機訪問
C. 沒有for和while語句,實現循環應該用遞歸
D. 默認惰性求值
2. 以下常用函數的類型註解錯誤的是(5分)
A. foldl :: (Foldable t)=>(a->b->b)->b->t a->b
B. id :: a->a
C. head :: [a]->a
D. map ::
(a->b)->[a]->[b]3. 表達式 map (+1) [1..10]的結果是____。 (5分)
4. 表達式 ((+1).(*2)) 3的結果是______。(5分)
5. 表達式foldl (xl _->[x:xs|x<-[1..n],xs<-xl,x `notElem` xs]) [[]] [1..n] where n=3的結果是___。(5分)
6. 請給出mapWithIndex :: (Int->a->b)->[a]->[b]的一個實現___________。(5分)
7. 寫出所有正偶數的列表t :: [Int] 的定義_____。(10分)
8. Maybe類型常用來表達一個可能存在的數據,它的定義如下
data Maybe a = Nothing | Just a
請完成函數除法函數maybeDiv :: Maybe Int -> Maybe Int -> Maybe
Int(5分)9. 請列出三個與Haskell相關的名詞(書、網站、工具鏈、Haskell的開源項目等)______________________________。(5分)
第三部分
附加題1. 用結構歸納法證明(寫書面證明,不是寫代碼),二叉樹最多有2^(h-1)-1個節點,h為二叉樹高度,定義為從根到所有葉子的路徑長度的最大值。二叉樹的定義為 data Tree = Nil | Node Tree Tree
2. 你之前學過哪些編程語言,你認為用它們解決問題的思路是什麼?你認為用Haskell語言來解決問題與其他語言有哪些異同?
3. 寫一段你認為最能體現函數式編程思想的代碼,語言不限(函數式與非函數式的語言都可以)
參考答案
第一部分
1.C
2.Nil | Cons Int IntList
3.C
4.B
5.(1)6 (2)8 (3)5 (4)無限循環
6.D
第二部分
1.B
2.A
3.[2..11]
4.7
5.[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
6.mapWithIndex f xs = zipWith f [0..] xs (其它合理實現均可,下同)
7.[2,4...]
8.import Control.Applicative
maybeDiv::Maybe Int -> Maybe Int -> Maybe Int
maybeDiv x y
| y==Just 0 = Nothing
| otherwise = (liftA2 div) x y
9.隨便寫啦
第三部分是面試題,就沒有標準答案啦,歡迎各位在評論區暢談自己的見解。
推薦閱讀:
※無類型Lambda演算筆記-2(Lambda可定義性,附Haskell實例)
※Kotlin強行模擬Point-Free
※GHC API 系列筆記(1):入門篇