什么是Scala的"强大"类型系统?

ryb*_*ome 30 types scala

讨论Scala时,类型系统始终被视为主要功能之一.它被称为强大的,并且是语言名字对象的主要原因(Scala是"可伸缩语言"的缩写).有人可以解释Scala键入的工作原理/为什么这个独特的,以及它如何有助于语言的可扩展性?

Dan*_*ral 46

我不认为现有的答案是恰当的.Scala有很多便利,但它们与类型系统无关,因为它们与类型有关.事实上,类型推断与类型系统的力量直接冲突 - 如果它不那么强大,可以有完整的类型推断(如在Haskell中).

所以,

  • Scala有成员的课程.(很明显,但我想在这里详尽无遗.)
  • scala类的方法("def")成员可以具有零个或多个参数列表,每个参数列表可以具有零个或多个参数,最后一个参数可以是vararg.
  • 参数可以通过值或名称传递.
  • 参数具有名称,可能具有默认值.
  • Scala有"var"和"val"成员(实际上也是方法).
  • 斯卡拉有"懒惰的"成员.
  • Scala具有"类型"成员(类型别名),可以指定为固定类型或类型边界.
  • Scala有抽象类和成员(以上所有成员都可能是抽象的).
  • Scala有内部类,特征和对象(Scala的内部类与Java不同).
  • Scala的成员,加上内部的东西,可能会被覆盖.
  • Scala具有类型继承.
  • Scala具有特征,提供类型线性化的多重继承.
  • Scala的traits的方法成员可能具有抽象覆盖(可堆叠,类似方面的覆盖).
  • Scala有单例类型.
  • Scala具有伴随类/对象(与范围相关).
  • Scala拥有私人,受保护和公共范围的课程,特征,单身人士和成员.
  • Scala的私有和受保护范围可以限制为任何封闭的包,类,特征或单例,加上"this".
  • Scala有自我类型.
  • Scala具有类型参数.
  • Scala的类型参数可以是共变量和反变量,也可以是不变量.
  • Scala具有类型构造函数.
  • Scala具有更高阶的类型.
  • Scala具有存在类型.
  • Scala具有结构类型.
  • Scala具有隐式参数.
  • Scala有函数类型,因为它们只是一个类加上语法糖,我不认为它属于这个列表.另一方面,函数类型是视图边界的一部分,所以也许它可以.
  • Scala有一个顶级(几乎每个人)和一个底部(像其他静态类型的fp语言).
  • Scala的"单位"是一种具有价值的类型(与其他地方的"无效"相对).

接下来,有一些与Scala的含义相关的功能,这是它们的优点.

  • Scala具有视图边界,这是一个隐式参数,其作用类似于另一种类型绑定.
  • Scala有上下文counds,一个隐含的参数,就像另一个绑定.
  • 一般而言,可以组合隐式参数和类型推断以在类型参数上构造任意复杂证明.

与上一个注释,implicits和类型推断相关联,使得Scala的类型系统turing完整.也就是说,您将任意程序编码为类型,编译器将在编译时"运行".这里证明,通过SKI微积分,在类型中有一个"越野车"无限循环作为进一步的演示.

上面的功能列表相当大,令人印象深刻.然而,Scala结合implicits和类型推断的方式在编译时生成静态证明(例如视图边界和上下文边界),这使得Scala的类型系统是唯一的.AFAIK,没有其他语言可以做到这一点,尽管肯定有其他语言通过其他方式提供证明功能.

  • @wberry嗯,这是[编译时的河内塔](https://gist.github.com/66925),让你入门.:-) (2认同)

sch*_*mmd 20

Scala类型系统优于Java的一些优点:

  1. 在许多情况下可以推断出类型,而不是明确指定.这更方便,但它促进了使用复杂的类型.

    val map = new Map[String, (String, String)]()

    代替

    Map<String, Tuple<String, String>> map = new HashMap<String, Tuple<String, String>>()

  2. 功能可以在类型系统中简单表达.如果你想看看它有多强大,可以考虑将番石榴库作为Java的解决方案.这是令人难以置信的约束和冗长(但仍然有用).

    val double = (x: Int) => x * 2

    而不是(使用番石榴)

    Function<Integer, Integer> double = new Function<Integer, Integer>() { @Override public Integer apply(Integer value) { return value * 2; }}

  3. 元组是Scala中的一种类型,它绕过了Java只能返回单个值的问题.

  4. Scala支持类型方差,因此当Cat是Thing的子类型时(或当反向关系成立时),您可以指定SomeObject是SomeObject的子类型.在java中,泛型不是协变的,这通常是有问题的.

  5. Scala使用特征支持有限形式的多重继承.与接口(其中多个可以用Java实现)不同,特征可以定义方法和变量.

  6. 数组像任何其他类一样透明地处理.

  7. 您可以通过隐式定义向现有类添加方法.例如,您可以向Arrays of Integers添加"sum"方法.

    class IntArray(value: Array[Int]) { def sumIt = value.reduceRight(_+_) }
    implicit def pimpArray(xs: Array[Int]) = new IntArray(xs)
    Array(1,2,3).sumIt
    
    Run Code Online (Sandbox Code Playgroud)

对于上述某些主题,这是另一个很好的资源:http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-5


Lan*_*dei 6

除了schmmd的优秀答案,Scala的类型系统还有更重要的功能:

  • objects是staticJava中成员变量和方法的一个干净的替代方法,例如,object它有自己的类型,可以作为参数传递
  • type 声明:您可以为复杂类型定义别名,例如 type FactorMap[A] = Map[A, Set[Int]]
  • 抽象类型成员作为泛型样式的替代
  • 自我类型
  • 结构类型
  • currying的多个参数列表
  • 隐式参数和转换,以及视图边界.这导致了"pimp my library"模式,可以用来模拟Haskell风格的类型类
  • 高阶类型

最后一点是我的最爱之一.例如,你不能用Java编写简单的通用仿函数接口.你需要 ......

public interface Function<A,B> {
   public B apply(A a);
}

//not valid Java
public interface Functor<C> {
   public <A,B> C<B> map(Function<A,B> fn, C<A> ca);
}
Run Code Online (Sandbox Code Playgroud)

如果你用一些具体的类型List来代替它,它就有效C.在Java中,您可以抽象出一个包含的内容(例如,通过编写`List),但是您不能在容器本身上进行抽象.相信我,我试图找到漏洞(结果就是这个).在Scala中,这是一件轻而易举的事:

trait Functor[C[_]] {
   def map[A,B](fn: A => B, ca: C[A]):C[B]
}

object ListFunctor extends Functor[List] {
   def map[A,B](fn: A => B, ca: List[A]):List[B] = ca.map(fn)
}
Run Code Online (Sandbox Code Playgroud)