zoukankan      html  css  js  c++  java
  • F#基本类型——Discriminated Unions

    定义Discriminated Unions:

    Discriminated Unions是F#的一种特有的数据类型,其基本语法格式如下:

        type type-name =
            | case-identifier1 [of type1 [ * type2 ...]
            | case-identifier2 [of type3 [ * type4 ...]
            ...

    Discriminated Unions主要用来表示在一组具有同一类型的子类型(可以看做一组具有共同基类的子类)。例如,我们要表示一套扑克中的四种花色:红桃、方块、梅花、黑桃,可以表示如下:

        type Suit =
             | Heart
             | Diamond
             | Spade
             | Club

    接下来,我们可以继续扩充它,来表示一整幅牌。在一副牌中,每张牌都都有四种类型。除了AJQK四张牌外,剩下的110都可以利用一个元组类型来关联四种牌型。则可以表示如下:

        type ValueCard =
           | 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)
            ]

    使用Discriminated Unions:

    Discriminated 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

    非常优雅而强大,这是那些没有模式匹配的语言所无法比拟的。

    C#实现Discriminated Unions

    正所谓条条大路通罗马,这种扑克牌的功能也可以用C#表示,首先拿花色来说,最直接的反应便是用枚举实现:
        enum Suit { Heart, Diamond, Spade, Club }

    然而这种方式存在一定隐患:我们可以很容易写出通过编译器检查的非法的花色
        var invalidSuit1 = Suit.Club | Suit.Diamond;

        var invalidSuite2 = (Suit) - 1;

    要避免这种隐患,可以通过如下两种方式:

    方式1

        class Suite
        {
            private Suite() { }

            static Suite()
            {
                Heart = new Suite();
                Diamond = new Suite();
                Spade = new Suite();
                Club = new Suite();
            }

            public static Suite Heart { get; private set; }
            public static Suite Diamond { get; private set; }
            public static Suite Spade { get; private set; }
            public static Suite Club { get; private set; }
        }

    方式2

        abstract class Suite { }
        class Heard : Suite { }
        class Diamond : Suite { }
        class Spade : Suite { }
        class Club : Suite { }

    由于F#C#本身是两种不同特性的语言,没有必要把其实现和C#一一对应起来(虽然确实可以一一对应起来),我并没有通过Reflector来看其具体对应着C#的实现。仅仅从功能上来讲,这两种方式都实现了我们预期的功能。 Discriminated Unions存在如下特性:

    1. 可实例化
    2. union case可以为不同的类型

    根据这两个特性来看,方式1不满足这两个条件,而方式2基本上和Discriminated Unions是等价的。接下来定义ValueCard时,方式1就不能满足需求,而方式2却仍然适用。因此,就像我前面所说的那样,Discriminated Unions可以看做一组具有共同基类的子类

    由于C#没有模式匹配,在接下来扑克牌规则的实现时,C#只能通过无数的if来模拟这种功能,代码几乎是F#的三倍左右,并且可维护性非常差。在这方面,F#以其独有的语法特性占有绝对的优势。

    参考文章:

    http://blog.csdn.net/minyskirt/archive/2009/12/15/5010779.aspx

  • 相关阅读:
    OSX: 私人定制Dock默认程序图标
    PHP+MYSQL分页原理
    Python 数据结构与算法 —— 哈弗曼树
    C#制作文本转换为声音的demo,保存音频文件到本地
    时区与时间(二)
    时区与时间(二)
    摄影的艺术
    摄影的艺术
    名词、文化概念的解释
    名词、文化概念的解释
  • 原文地址:https://www.cnblogs.com/TianFang/p/1655226.html
Copyright © 2011-2022 走看看