我读到 Scala 的类型系统被 Java 互操作性削弱了,因此无法执行与 Haskell 类型系统相同的一些功能。这是真的?是因为类型擦除的弱点,还是我在各方面都错了?这种差异是 Scala 没有类型类的原因吗?
6 回答
最大的区别在于 Scala 没有 Hindley-Milner 全局类型推断,而是使用一种局部类型推断形式,要求您指定方法参数的类型以及重载或递归函数的返回类型。
这不是由类型擦除或 JVM 的其他要求驱动的。这里所有可能的困难都可以克服,并且一直是,只要考虑 Jaskell - http://docs.codehaus.org/display/JASKELL/Home
HM 推理在面向对象的上下文中不起作用。具体来说,当使用类型多态时(与类型类的临时多态相反)。这对于与其他 Java 库的强互操作以及(在较小程度上)从 JVM 获得最佳优化至关重要。
说 Haskell 或 Scala 具有更强大的类型系统是不正确的,只是它们不同而已。两种语言都在向不同的方向推动基于类型的编程的界限,并且每种语言都具有彼此难以复制的独特优势。
Scala 的类型系统与 Haskell 的不同,尽管 Scala 的概念有时直接受到 Haskell 的优势及其知识渊博的研究人员和专业人士社区的启发。
当然,在最初并非主要用于函数式编程的 VM 上运行会产生与针对该平台的现有语言的一些兼容性问题。因为大多数关于类型的推理发生在编译时,Java(作为一种语言和作为一个平台)在运行时的限制是没有什么可担心的(除了类型擦除,虽然这个错误似乎使集成到 Java生态系统更加无缝)。
据我所知,Java 在类型系统级别上的唯一“妥协”是处理原始类型的特殊语法。虽然 Scala 甚至不再允许原始类型,但它接受具有该错误的旧 Java 类文件。也许您已经看过类似List[_]
(或更长的等效代码List[T] forSome { type T }
)的代码。这是与 Java 的兼容特性,但在内部也被视为存在类型,不会削弱类型系统。
Scala 的类型系统确实支持类型类,尽管方式比 Haskell 更冗长。我建议阅读这篇论文,这可能会对 Scala 类型系统的相对优势产生不同的印象(第 17 页的表格很好地列出了非常强大的类型系统概念)。
Scala 和 Haskell 的编译器用来推断类型的方法不一定与类型系统的强大相关,尽管它对人们编写代码的方式有一些影响。拥有强大的类型推断算法可以使编写更抽象的代码变得值得(您可以自己决定这是否在所有情况下都是一件好事)。
最终,Scala 和 Haskell 的类型系统的驱动力是希望为用户提供解决问题的最佳工具,但朝着这个目标采取了不同的路径。
另一个需要考虑的有趣点是 Scala 直接支持经典的 OO 风格。这意味着,存在子类型关系(例如,List 是 Seq 的子类)。这使得类型推断更加棘手。除此之外,您可以在 Scala 中混合使用特征,这意味着给定类型可以具有多个超类型关系(使其更加棘手)
我对 Haskell 的经验很少,但我注意到 Scala 类型系统与 Haskell 不同的最明显的一点是类型推断。
在 Scala 中,没有全局类型推断,您必须显式告知函数参数的类型。
例如,在 Scala 中你需要这样写:
def add (x: Int, y: Int) = x + y
代替
add x y = x + y
当您需要适用于各种类型的通用版本的 add 函数具有“+”方法时,这可能会导致问题。有一个解决方法,但它会变得更加冗长。
但在实际使用中,我发现 Scala 的类型系统对于日常使用来说已经足够强大了,而我几乎从不将这些变通方法用于泛型,这可能是因为我来自 Java 世界。
显式声明参数类型的限制并不是一件坏事,无论如何你都需要记录它。
那么它们是图灵可约的吗?
请参阅 Oleg Kiselyov 的页面http://okmij.org/ftp/ ... 可以在 Haskell 的类型系统中实现 lambda 演算。如果 Scala 可以做到这一点,那么在某种意义上,Haskell 的类型系统和 Scala 的类型系统计算相同的类型。问题是:一个比另一个自然吗?一个比另一个优雅吗?