• 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

  • 相关阅读:
    FR5一二维码设置条码值
    is application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem
    sql server 2012插入排序后的数据到临时表无效
    Fr3设置图片打印
    created a ThreadLocal with key of type [oracle.jdbc.driver.AutoKeyInfo$1]
    jdbc oracle 连接串
    初玩PLSQL连接 Oracle
    java.lang.NumberFormatException: For input string: "F"
    网站被截持到赌博网
    java时间差
  • 原文地址:https://www.cnblogs.com/TianFang/p/1655226.html
Copyright © 2020-2023  润新知