1.5 练习

下面的练习用于测试读者对 Scala 编程知识的掌握程度,其覆盖了本章的内容和其他Scala特性。练习8和9对比了并发编程和分布式编程的区别。读者并不需要编写完整的Scala程序,可以用伪代码来解答练习中的问题。

1.实现一个具有如下类型声明的compose方法。此方法必须返回一个函数h,它是输入函数f和g的组合。

    def compose[A, B, C]
    (g: B => C, f: A => B): A => C = ???

2.实现一个具有如下类型声明的fuse方法,若a和b都非空,则返回的Option对象应该包含Option对象a和b中的值的二元组(使用for推导式)。

    def fuse[A, B]
    (a: Option[A], b: Option[B]): Option[(A, B)] = ???

3.实现一个check方法,其参数是类型为T的值的序列和类型为T => Boolean的函数,当且仅当 pred 函数对 xs 中所有的值都为真,并且不会抛出异常时,check才返回真。

    def check[T](xs: Seq[T])(pred: T => Boolean): Boolean = ???

check的使用方法如下。

    check(0 until 10)(40 / _ > 0)

check方法使用的是柯里化定义,即两个参数没有用一个链表表示,而是用两个链表表示。柯里化定义让函数调用语法更优雅,而且语义上等价于单个参数链表的定义方式。

4.修改本章的Pair类,使它能够用于模式匹配。

如果读者从未做过,可以先熟悉一下Scala中的模式匹配。

5.实现一个permutations函数,它将一个字符串变换为一个字符串序列,结果中每一个字符串都是输入字符串字母顺序的变换结果。

    def permutations(x: String): Seq[String]

6.实现一个combinations函数,输入是一个元素序列,输出是长度为n的所有可能组合的遍历器。组合指的是从一个元素集合中选出一个子集的方式,每个元素只被选择一次,只不过不关心元素子集中的次序。比如,给定序列 Seq(1, 4, 9, 16),长度为2的组合包括Seq(1, 4)、Seq(1, 9)、Seq(1, 16)、Seq(4, 9)、Seq(4, 16)和 Seq(9, 16)。combinations 函数的定义声明如下(参见标准库文档中Iterator的API)。

    def combinations(n: Int, xs: Seq[Int]): Iterator[Seq[Int]]

7.实现一个方法,输入是一个正则表达式,输出是一个部分函数。部分函数将一个字符串映射为此字符串中的匹配链表。

    def matcher (regex: String): PartialFunction[String, List[String]]

如果没有找到匹配项,则这个部分函数不需要定义;否则此函数使用正则表达式输出匹配链表。

8.假设读者和同事们同处一个办公室,各自有一个隔间,大家互相看不见对方,且不能说话(会吵到别人)。因为都被限制在隔间中,所以每个人都无法确认传递聚会消息的纸条是否已经到达目的地。在某一时刻,其中一人被叫到老板办公室,被永久“扣留”在那里。请设计一个算法,使大家能够确定何时能够聚会。除被老板叫走的那位之外,所有人都需要同时做出决定。如果有些纸条被递到目的地时发生随机性失误,则该如何改进算法?

9.在练习8中,假设读者和同事们所在的办公室旁的大厅中有一个白板。每个人可以偶尔穿过大厅,并在白板上写字,但无法保证哪两个人能同时出现在大厅中。在这种设定下设计一个算法解决同时确定时间的问题,即用白板替代练习8中的纸条。