F#程序设计-函数式编程之Discriminated Unions

来源:互联网 发布:c语言考公共基础知识吗 编辑:程序博客网 时间:2024/05/22 12:14

discriminated union是函数式编程中的一个基础类型,要定义discriminated union类型,需要用到type关键字,后面接着的是discriminated union类型的名字,然后用"|"分隔每一个值。在discriminated union类型中的每一个值都被称作为union case。例如一套扑克有四种牌,红桃、方块、梅花、黑桃。我们可以定义一套牌的discriminated union类型:

> type Suit =
-      | Heart
-      | Diamond
-      | Spade
-      | Club;;

type Suit =
  | Heart
  | Diamond
  | Spade
  | Club

 

> let suits = [ Heart; Diamond; Spade; Club ];;

val suits : Suit list = [Heart; Diamond; Spade; Club]

 

你也可以利用union case把可选的数据关联起来,比如下面的例子,在一副牌中,每张牌都都有四种类型。除了A、J、Q、K四张牌外,剩下的1到10都可以利用一个元组类型来关联四种牌型。

type PlayingCard =
  | Ace of Suit
  | King of Suit
  | Queen of Suit
  | Jack of Suit
  | ValueCard of int * Suit

> let deckOfCards =
-     [
-         for suit in [ Spade; Club; Heart; Diamond ] do
-             yield Ace(suit)
-             yield King(suit)
-             yield Queen(suit)
-             yield Jack(suit)
-             for value in 2 .. 10 do
-                 yield ValueCard(value, suit)
-      ];;

val deckOfCards : PlayingCard list =
  [Ace Spade; King Spade; Queen Spade; Jack Spade; ValueCard (2,Spade);
   ValueCard (3,Spade); ValueCard (4,Spade); ValueCard (5,Spade);
   ValueCard (6,Spade); ValueCard (7,Spade); ValueCard (8,Spade);
   ValueCard (9,Spade); ValueCard (10,Spade); Ace Club; King Club; Queen Club;
   Jack Club; ValueCard (2,Club); ValueCard (3,Club); ValueCard (4,Club);
   ValueCard (5,Club); ValueCard (6,Club); ValueCard (7,Club);
   ValueCard (8,Club); ValueCard (9,Club); ValueCard (10,Club); Ace Heart;
   King Heart; Queen Heart; Jack Heart; ValueCard (2,Heart);
   ValueCard (3,Heart); ValueCard (4,Heart); ValueCard (5,Heart);
   ValueCard (6,Heart); ValueCard (7,Heart); ValueCard (8,Heart);
   ValueCard (9,Heart); ValueCard (10,Heart); Ace Diamond; King Diamond;
   Queen Diamond; Jack Diamond; ValueCard (2,Diamond); ValueCard (3,Diamond);
   ValueCard (4,Diamond); ValueCard (5,Diamond); ValueCard (6,Diamond);
   ValueCard (7,Diamond); ValueCard (8,Diamond); ValueCard (9,Diamond);
   ValueCard (10,Diamond)]

 

 discriminated union类型也可以递归。如果你想定义一个相互递归的discriminated unions,可以像定义函数一样,不同的是它们必须用and关键字连在一起。例如,在下面的代码中,我们定义了一个编程语言的简单格式:

type Statement =
    | Print of string
    | Sequence of Statement * Statement
    | IfStmt of Expression * Statement * Statement
and Expression =
    | Integer of int
    | LessThan of Expression * Expression
    | GreaterThan of Expression * Expression

 

为了表达一个if语句:

if (3 > 1)
print "3 is greater than 1"
else
print "3 is not"
print "greater than 1"

 

在上面定义的简单的语言格式中,我们可以利用递归来实现if语句的表达式:

let program =
    IfStmt(
        GreaterThan(
            Integer(3),
            Integer(1)
        ),
        Print("3 is greater than 1"),
        Sequence(
            Print("3 is not"),
            Print("greater than 1")
        )
    )

 

 在树结构中运用Discriminated Unions

Discriminated unions类型非常适合用于代表树形结构,下面的代码定义了一个二叉树,并且用一个函数来遍历并打印出这棵树:

type BinaryTree =
    | Node of int * BinaryTree * BinaryTree
    | Empty

 

let rec printInOrder tree =
        match tree with
        | Node (data, left, right)
            ->  printInOrder left
                printfn "Node %d" data
                printInOrder right
        | Empty
            -> ()

 

比如,我们想生成下面这样的一颗树:

 2

/ /

1 4
/ /
3 5

 

就可以这样编写代码:

let binTree =
    Node(2,
        Node(1, Empty, Empty),
        Node(4,
            Node(3, Empty, Empty),
            Node(5, Empty, Empty)
            )
        )

 

 printInOrder tree

 

模式匹配

discriminated unions同样也可以用于模式匹配,在匹配规则中,用unions case来作为模式标签。如果一个unions标签用数据关联,你就可以根想在正常的模式匹配中样使用模糊匹配或者值匹配。下面的例子还是通过玩纸牌的游戏来说明模式匹配:

let describeHoleCards cards =
    match cards with
    | []
    | [_]
        -> failwith "Too few cards."
    | cards when List.length cards > 2
        -> failwith "Too many cards."
    | [ Ace(_); Ace(_) ] -> "Pocket Rockets"
    | [ King(_); King(_) ] -> "Cowboys"
    | [ ValueCard(2, _); ValueCard(2, _)]
        -> "Ducks"
    | [ Queen(_); Queen(_) ]
    | [ Jack(_); Jack(_) ]
        -> "Pair of face cards"
    | [ ValueCard(x, _); ValueCard(y, _) ] when x = y
        -> "A Pair"
    | [ first; second ]
        -> sprintf "Two cards: %A and %A" first second

原创粉丝点击