## 理解F#中的模式匹配与活动模式

2008-11-25 23:09  Anders Cui  阅读(2842)  评论(7编辑  收藏

F# Code - 对简单值和.NET类型进行匹配// 对简单值进行匹配。let rec fibonacci x =    match x with    | x when x <= 0 -> failwith "x必须是正整数。"    | 1 -> 1    | 2 -> 1    | x -> fibonacci(x - 1) + fibonacci(x - 2)  printfn "%i" (fibonacci 2) // -> 1printfn "%i" (fibonacci 4) // -> 3// 对.NET类型进行匹配。open Systemlet typeToString x =    match box x with    | :? Int32 -> "Int32"    | :? Double -> "Double"    | :? String -> "String"    | _ -> "Other Type"

F# 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 listOfListprint_any primes // [2; 3; 5; 7; 11; 13; 17; 19; 23; 29]

F# Code - 对Union类型应用模式匹配type BinaryTree<'a> =    | Leaf of 'a    | Node of BinaryTree<'a> * BinaryTree<'a>     let rec printBinaryTreeValues t =    match t with    | Leaf x -> printfn "%i" x    | Node (l, r) ->        printBinaryTreeValues l        printBinaryTreeValues r        printBinaryTreeValues (Node ((Node (Leaf 1, Leaf 2)), (Node (Leaf 3, Leaf 4))))

Single-Case活动模式

Single-Case是最简单的活动模式形式，它将一个输入值转换为其它的值，比如：

F# Code - Single-Case活动模式let (|UpperCase|) (x:string) = x.ToUpper()let result = match "foo" with             | UpperCase "FOO" -> true             | _ -> false             printfn "%b" result // -> true

UpperCase模式看起来像是一个函数，不过对于函数来说，没法直接应用模式匹配的语法。

Multi-Case活动模式

F# Code - Multi-Case活动模式let (|Odd|Even|) x = if x % 2 = 0 then Even else Oddlet isDivisibleByTwo x = match x with Even -> true | Odd -> falseprint_any (isDivisibleByTwo 2) // -> trueprint_any (isDivisibleByTwo 3) // -> false

Partial活动模式

F# Code - Partial活动模式// Partial Active Patternsopen Systemlet (|DivisibleBySeven|_|) input = if input % 7 = 0 then Some() else Nonelet (|IsPerfectSquare|_|) (input : int) =    let sqrt = int (Math.Sqrt(float input))    if sqrt * sqrt = input then        Some()    else        Nonelet describeNumber x =    match x with    | DivisibleBySeven & IsPerfectSquare ->         printfn "x is divisible by 7 and is a perfect square."    | DivisibleBySeven                   -> printfn "x is divisible by seven."    | IsPerfectSquare                    -> printfn "x is a perfect square."    | _                                  -> printfn "x looks normal."    describeNumber 49 // x is divisible by 7 and is a perfect square.describeNumber 35 // x is divisible by seven.describeNumber 25 // x is a perfect square.describeNumber 20 // x looks normal.

F# Code - 应用活动模式操作XML文档// 定义针对XML节点的模式let (|Node|Leaf|) (node : #System.Xml.XmlNode) =     if node.HasChildNodes then         Node (node.Name, { for x in node.ChildNodes -> x })     else         Leaf (node.InnerText)// 打印XML节点的函数 let printXml node =     let rec printXml indent node =         match node with         | Leaf (text) -> printfn "%s%s" indent text         | Node (name, nodes) ->             printfn "%s%s:" indent name             nodes |> Seq.iter (printXml (indent + "    "))     printXml "" node     // 定义XML节点let doc =    let temp = new System.Xml.XmlDocument()    let text =  "<fruit>                 <apples>                     <gannySmiths>1</gannySmiths>                     <coxsOrangePippin>3</coxsOrangePippin>                 </apples>                 <organges>2</organges>                 <bananas>4</bananas>             </fruit>"    temp.LoadXml(text)    tempprintXml (doc.DocumentElement :> System.Xml.XmlNode)

（要了解本人所写的其它F#随笔请查看 F#系列随笔索引

Introduction to F# Active Patterns by Chris Smith