ZJU Lambda
首发于ZJU Lambda

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.随便写啦

第三部分是面试题,就没有标准答案啦,欢迎各位在评论区畅谈自己的见解。

编辑于 2017-10-09

文章被以下专栏收录