Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala类型系统如何知道cons+;零是详尽的吗?_Scala_Type Systems_Algebraic Data Types - Fatal编程技术网

Scala类型系统如何知道cons+;零是详尽的吗?

Scala类型系统如何知道cons+;零是详尽的吗?,scala,type-systems,algebraic-data-types,Scala,Type Systems,Algebraic Data Types,我刚刚编写了这个函数,想知道如果忽略Nil的情况会发生什么,并注意到scalac给了我一个警告: def printList[String](list: List[String]) { list match { case head :: tail => { println(head) printList(tail) } //case Nil => println("Done")

我刚刚编写了这个函数,想知道如果忽略Nil的情况会发生什么,并注意到scalac给了我一个警告:

def printList[String](list: List[String]) {
    list match {
        case head :: tail => {
            println(head)
            printList(tail)
        }
        //case Nil => println("Done")
    }
}
警告:匹配可能并不详尽。
它将在以下输入时失败:Nil

我很难确定到底发生了什么。我了解递归数据类型上的模式匹配的一般概念,直到您穷尽所有案例,但我不清楚这如何映射到Scala类型系统。具体来说,我正在查看Scala标准库的源代码,并想知道:

  • Scala究竟在代码中的什么地方得到了这样的想法:完成List类实例的match语句需要一个基本用例?人们当然可以想象一种代数数据类型,这种数据类型“一直在运行”,没有基本情况
  • 代码中的具体位置是scala.collection.immutable.Nil,特别是指定为List类的基本情况

  • 其实并不像你想象的那么复杂
    List
    是一个
    密封的抽象类
    ,有两个实现,
    Nil
    (是的,这是类的名称)。这里的重要部分是
    密封的
    修饰符。这只要求实现
    List
    的任何类必须与
    List
    本身位于同一源文件中

    sealed
    的重要性在于,现在编译器可以肯定地知道
    List
    的每个可能实现者,因此,如果您对列表进行模式匹配,编译器可以确定您的模式匹配块是否详尽无遗

    最后要意识到的一点是,
    中存在一些语法上的糖分。通常,如果您有一些案例类:

    case class Foo(a: String, b: Int)
    
    你会像这样匹配它的

    x match {
      case Foo(a, b) => //...
    }
    
    但是,如果案例类正好有两个成员,也可以这样编写:

    x match {
      case a Foo b => //...
    }
    
    因此,在您的模式匹配声明中,您确实在做:

    list match {
            case ::(head, tail) => {
    

    所以实际上,您所做的只是检查列表是否是
    的实例。因此,编译器可以看到您从未检查列表是否为
    Nil
    的实例,并向您发出警告。

    您可以查看
    list
    的源代码。基本用例没有什么特别的地方,只是
    List
    被声明为
    sealed
    ,然后只有两个类扩展它:

    sealed abstract class List[+A] ...
    case object Nil extends List[Nothing] { ... }
    final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] { ... }
    
    Scala编译器可以很容易地确定密封特征或抽象类是否完全匹配,因为它可以确定单个文件中可能匹配的范围。说:

    如果模式匹配的选择器是密封类的实例,则模式匹配的编译可能会发出警告,诊断给定的模式集不是详尽的,即在运行时可能会引发
    MatchError


    Scala类型匹配实现的血淋淋的细节如下:对于
    Nil
    来说,这并不是说存在“基本情况”<代码>列表是密封的,因此编译器知道要在匹配中查找哪些类型,即
    Nil
    。当其中一个缺失时,这是一个相当好的暗示,表明这不是一个完整的匹配。哦,这太令人失望了。我以为它在做一些像OCaml一样的分解魔法。感谢您引用规范中的相关段落。