3.3.4.2用 F# 求列表中数字的和
我们已经知道了用 C# 实现的代码,现在,再尝试用 F# 实现同样的功能。清单 3.16 是F# 函数 sumList,并用几个F# Interactive 命令进行了测试。
清单 3.16对列表中元素求和(F# Interactive)
> let rec sumList list =
match list with <- 根据模式,匹配列表
| []-> 0 [1]
|head::tail -> head + sumList(tail) [2]
;;
val sumList : int list -> int [3]
> let list = [ 1 .. 5 ];; <- 创建测试列表
val list : int list
> sumList(list);; <- 计算,输出和
val it : int = 15
如果和前面用 C# 实现的代码相比,会发现有很多相似之处。与前面的情况一样,有两个分支,一个用于为空列表[1],一个用于 cons cell [2],第二个分支也使用递归实现。显著的区别在于,F# 可以使用模式匹配选择执行路径。模式匹配还能从 cons cell 中提取值,因此,执行一旦进入第二个分支, head 和 tail 的值就有了。因此,不会使用到没有被模式匹配的值,能增加了代码的稳健性。这听起来微不足道,但能防止代码意外地试图访问(不存在)空列表的元素。模式匹配是函数语言天生的结构,C# 中没有对应的功能,所以,只能使用条件运算符(?:)来实现相同的行为。
另外,F# 类型推断还有帮助:不必在代码中显式指定类型。可以看到,它正确推断出函数取一个整数列表,返回整数[3]。推理算法测试 list 值是空列表,或cons cell,推断出值的类型是列表。从一个分支将返回 0,可知整个函数返回整数;因为,我们是把列表中的元素加到一起,可以推断出参数是包含整数的列表。
这一节中的递归概念非常重要,但是,写递归很难。在下一节,我们将介绍一种机制,能够隐藏代码中困难的递归部分。
----------
[4] 我们可以在代码中添加对 foreach 语句的支持,对于FuncList 类型,这样做是值得的。