2.3.2.1 使用高阶函数扩展词汇

来源:互联网 发布:淘宝怎么看付款顺序 编辑:程序博客网 时间:2024/05/16 12:34

2.3.2.1 使用高阶函数扩展词汇

 

处理集合,最能体现高阶函数使代码更具声明性。在 C# 中,是通过扩展方法(如 Where 和 Select),使之成为 LINQ 的一部分而实现的,因为能用 LINQ 查询写的一切,都可以用把 Func(函数)委托作为参数的方法来写。

在这一节,我们将用 F# 列表写同样的代码,来演示 F# 的几个重要方面。我们还没有看到真正的 F# 代码,更多地是从宏观上层面理解的。清单 2.3 中的第一个示例是从列表中筛选出奇数;第二个示例先筛选出数字,然后计算每个数的平方。

 

清单 2.3 用高阶函数处理列表 (F# Interactive)

 

> let numbers = [ 1 .. 10 ]

let isOdd(n) = n % 2 = 1  [1]

let square(n) = n * n     [2]

;;

val numbers : int list    | [3]

val isOdd : int -> bool   |

val square : int –> int   |

 

> List.filter isOdd numbers;;  [4]

val it : int list = [1; 3; 5; 7; 9]

 

> List.map square (List.filter isOddnumbers);;  [5]

val it : int list = [1; 9; 25; 49; 81]

 

我们首先实现了两个函数,在后面处理列表时会用到。第一个函数判断作为参数的数字是否是奇数[1],第二个函数返回给定整数的平方[2]。回想一下第一章,F# 编译器能够自动推导出我们输入的表达式类型,因此,也能推断出函数的类型[3]。我们将在这一章的后面和第三章中谈论 F # 中的类型,详细探讨输出的类型签名(type signatures)和函数声明。

清单 2.3 显示了高阶函数在表示问题时扩展词汇的能力。在第一个示例中,我们使用高阶函数List.filter,它的第一个参数值是函数,第二个参数值是列表[4],函数判断数字是否为奇数,列表是从 1 到 10 的数。在下一行上,可以看到结果是包含这个范围内所有奇数的列表。

以命令风格,我们通常会用 for 循环或类似的结构实现。正如我们在第一章中了解的,命令式语言只提供有限的方法,组合基本命令,for 循环就是其中之一。刚才我们看到的这个示例实现了一个新的控制结构,用于组合命令。List.filter 函数以抽象方式描述处理列表的特定模式,但这个模式是可重用的,因为我们可以用函数指定筛选的行为。高阶函数是函数编程的核心概念,我们将在第六章再次讨论,你将看到,高阶函数能够用来处理大多数的数据结构。

在第二个示例[5],我们把第一个示例中的整个表达式作为参数值传递另一个函数。这一次我们使用 List.map,它把第一个参数值,即函数应用到给定列表所有值上,在我们的示例中,它计算所有奇数的平方。代码虽然仍是声明式的,但并未做到应有的可读性。一个原因是,这个表达式的第一个结构是 List.map,但 List.map 实际上是最后执行的操作。F# 是一种灵活的语言,能够解决这个问题。我们看看另一个功能,管道(pipelining),能使代码更清楚。

0 0