• F#学习:理解什么是“可区分联合”(Discriminated Union)


    // 下面首先定义了几个类型的简略形式(Type abbreviations),在编译时会被扩展为其真正的类型,
    // 如下列的 int, string.
    // 而其字面的缩略名称(Route, Make, Model)则可能消失。
    type Route = int
    type Make = string
    type Model = string
    
    // 这里定义了一个“可区分的联合”(Discriminated Union)
    // 通过观察编译生成的代码发现:首先 Transport 被编译为了一个抽象类;
    // 接下来,Car, Bicycle, Bus 被做成了内嵌在 Transport 中的,Transport 类的 public 子类。
    // 并且,Transport 类含有一系列 static 的 factory method 用于创建几种不同类型的实例:
    // Car, Bicycle, Bus.
    // 
    // 因此“可区分联合”大致上可以这样理解:它定义了几个事务的类型及其父子层次关系(使其可“区分”)
    //
    // Transport 是一个抽象类型;
    // Car, Bicycle, Bus 都属于 Transport 类型,但是是它的子类
    // 其含有的属性集合,构造器也各有不同。比如 Car 包含两个 string 属性 (Make 和 Model).
    // Bus 包含一个 int 型的属性
    // 而 Bicycle 则是一个简单的标记性的子类,不具有数据成员,只是用于区分不同的子类型而已。
    type Transport = 
        | Car of Make * Model
        | Bicycle
        | Bus of Route
    
    let nick = Car("BMW", "360")
    // 定义一个列表,其第一个元素是 Bicycle, 第二个是 Bus. 列表类型可以理解为是 List<Transport>
    let don = [ Bicycle; Bus 8 ]
    // 类似上面。
    let james = [ Car ("Ford", "Fiesta"); Bicycle ]
    
    // 进行具体类型判断的模式匹配
    // 由于这里只用了最简单的“类型判断”的模式匹配语法,实际编译后
    // 会被简单的翻译为类似 C# 代码的:
    // if (x is Car) {
    //   ...
    // } else if (x is Bicycle) {
    //   ..
    // }
    // ...
    // 当然,模式匹配是很强大的,并不限于类型判断。这只是最简单的一种情况而已。
    match nick with
        | Car _ -> printfn "Car"
        | Bicycle -> printfn "Bicycle"
        | Bus _ -> printfn "Bus"
    
    System.Console.ReadLine() |> ignore

    可区分的联合也可以含有成员 (member). 如下列代码示例给二叉树添加了一个 Size 属性:

    type Tree<'T> =
        | Node of 'T * Tree<'T> * Tree<'T>
        | Tip
    
        member t.Size =
            match t with
                | Node(_, l, r) -> 1 + l.Size + r.Size
                | Tip -> 0
    
    let t: Tree<char> = Node('a', Node('b', Tip, Node('c', Tip, Node('d', Tip, Tip))), Tip)
    printfn "%d" t.Size
    
    System.Console.ReadLine() |> ignore

    以上用了模式匹配的语法来计算节点数(忽略了 Tip)。即:

    二叉树树的节点数 = 1(当前节点)+ l.Size (左子树节点数) + r.Size (右子树节点数)

    这里显然用了一个递归,我们用 Reflector 看看编译生成的代码:

    public int Size
    {
        get
        {
            if (this is _Tip<T>)
            {
                return 0;
            }
            Node<T> node = (Node<T>) this;
            Program.Tree<T> r = node.item3;
            Program.Tree<T> l = node.item2;
            return ((1 + l.Size) + r.Size);
        }
    }
     

    可以发现该代码仍然使用的递归,而没有做任何优化(大概是因为该算法不是尾递归所以无法做自动优化)。

  • 相关阅读:
    2015.07.20MapReducer源码解析(笔记)
    Hive(笔记)
    HDFS入门(1)
    Zookepper(2015.08.16笔记)
    USB_ModeSwitch 介绍(转)
    Perl 模块 Getopt::Std 和 Getopt::Long
    在linux下设置开机自动启动程序的方法
    gcc Makefile 入门
    Linuxexec函数族及system函数
    signal(SIGHUP, SIG_IGN)的含义
  • 原文地址:https://www.cnblogs.com/RChen/p/1786510.html
Copyright © 2020-2023  润新知