F#探险之旅(二):函数式编程(下) - 面向对象网 f# 学习 对象 - 面向对象技术开发

面向对象技术开发

会员投稿 投稿指南 站长资讯通告:
您的位置: 首页 > OOP语言 > F# > 正文

F#探险之旅(二):函数式编程(下)

来源: www.bianceng.cn 阅读:

模式匹配(Pattern Matching)

模式匹配允许你根据标识符值的不同进行不同的运算。有点像一连串的if...else结构,也像C++和C#中的switch,但是它更为强大和灵活。

看下面Lucas序列的例子,Lucas序列定义跟Fibonacci序列一样,只不过起始值不同:

Code
let rec luc x =
  match x with
  | x when x <= 0 -> failwith "value must be greater than zero"
  | 1 -> 1
  | 2 -> 3
  | x -> luc(x - 1) + luc(x - 2)

printfn "(luc 2) = %i" (luc 2)
printfn "(luc 6) = %i" (luc 6)

这里可以看到模式匹配的简单应用,使用关键字match和with,不同的模式规则间用“|”隔开,而“->”表示如果该模式匹配,运算结果是什么。

这个例子的打印结果为:

Output
(luc 2) = 3
(luc 6) = 18

匹配规则时按照它们定义的顺序,而且模式匹配必须完整定义,也就是说,对于任意一个可能的输入值,都有至少一个模式能够满足它(即能处理它);否则编译器会报告一个错误信息。另外,排在前面的规则不应比后面的更为“一般”,否则后面的规则永远不会得到匹配,编译器会报告一个警告信息,这种方式很像C#中的异常处理方式,在捕获异常时,我们不能先不会“一般”的Exception异常,然后再捕获“更具体”的NullReferenceException异常。

可以为某个模式规则添加一个when卫语句(guard),可将when语句理解为对当前规则的更强的约束,只有when语句的值为true时,该模式规则才算匹配。在上例的第一个规则中,如果没有when语句,那么任意整数都能够匹配模式,加了when语句后,就只能匹配非正整数了。对于最简单的情况,我们可以省略第一个“|”:

Code
let boolToString x =
  match x with false -> "False" | _ -> "True"

这个例子中包含两个模式规则,“_”可以匹配任意值,因此当x值为false时匹配第一个规则,否则就匹配第二个规则。

另一个有用的特性是,我们可以合并两个模式规则,对它们采取相同的处理方式,这个就像C#中的switch…case结构中可以合并两个case一样。

Code
let stringToBool x =
  match x with
  | "T" | "True" | "true" -> true
  | "F" | "False" | "false" -> false
  | _ -> failwith "Invalid input."

在本例中,我们把三种模式规则合并在了一起,将字符串值转换为相应的布尔值。

可以对大多数F#中定义的类型进行模式匹配,下面的例子就展示了对元组进行匹配。

Code
let myOr b1 b2 =
  match b1, b2 with
  | true, _ -> true
  | _, true -> true
  | _ -> false

let myAnd p =
  match p with
  | true, true -> true
  | _ -> false

这两个函数说明了如何对元组应用模式匹配,它们的功能是求两个布尔值“或”和“且”运算的结果。在myOr中,从第一、二两个模式规则可以知道b1、b2只要有一个为true,计算结果就是true,否则为false。myOr true false的结果为true,myAnd(true, false)结果为false。

模式匹配的常见用法是对列表进行匹配,事实上,对列表来说,较之if…then…else结构,模式匹配的方式更好。看下面的例子:

Code
let listOfList = [[2; 3; 5]; [7; 11; 13]; [17; 19; 23; 29]]
let rec concatenateList list =
  match list with
  | head :: tail -> head @ (concatenateList tail)
  | [] -> []

let rec concatenateList2 list =
  if List.nonempty list then
    let head = List.hd list in
    let tail = List.tl list in
    head @ (concatenateList2 tail)
  else
    []

let primes = concatenateList listOfList
print_any primes

listOfList是一个列表的列表,两个函数concatenateList和concatenateList2的功能都是将listOfList的元素连接为一个大的列表,只不过一个用模式匹配方式实现,一个使用if…then…else结构实现。可以看到使用模式匹配的代码更为简洁明了。观察concatenateList函数,它处理列表的方式是先取出列表的头元素(head),处理它,然后递归地处理剩余元素,这其实是通过模式匹配方式处理列表的最常见的方式(但不是唯一的方式)。

在F#中,模式匹配还可用在其它地方,在后面的文章中将陆续介绍。

Tags:
相关文章列表: