Scala类型系统相对于Haskell的缺点是什么?

56

我读到Scala的类型系统与Java互操作性相克,并且不能像Haskell的类型系统那样执行一些功能。 这是真的吗? 这种弱点是由于类型擦除,还是我完全错了? 这种差异是Scala没有类型类的原因吗?


1
你可能想要阅读这个链接:http://lambda-the-ultimate.org/taxonomy/term/32 - James Black
4
就我所知,Haskell 的类型擦除程度至少与 Scala 相当,具体价值如何则不得而知。 - C. A. McCann
6个回答

54

Scala与Haskell的最大区别在于,Scala没有Hindley-Milner全局类型推断,而是使用一种本地类型推断形式,需要你为方法参数指定类型以及递归函数的返回类型或重载函数的返回类型。

这不是由类型擦除或JVM的其他要求驱动的。所有可能的困难都可以克服,并且已经解决了,只需考虑Jaskell - http://docs.codehaus.org/display/JASKELL/Home

H-M推理在面向对象的上下文中不起作用。具体来说,当使用类型多态性时(而不是类型类的特殊多态性)时,这非常关键,以实现与其他Java库的强交互,以及(在较小程度上)获得最佳的JVM优化。

不太合适地宣称Haskell或Scala拥有更强的类型系统,只能说它们不同。这两种语言正在不同方向推进基于类型的编程的边界,每种语言都具有独特的优势,很难在另一种语言中复制。


第16章演示了Scala的数据类型和模式匹配,开发了一个H/M风格的类型推断系统。http://www.scala-lang.org/docu/files/ScalaByExample.pdf - oluies
4
“H-M 推断在面向对象的上下文中不起作用。”但 F# 实现了 H-M,并且具有面向对象的一面。 - Mauricio Scheffer
10
@Mauricio:是的,OCaml甚至是一个更好的反例,因为它会推断类类型... - J D
1
Jaskell在编译时根本不检查类型,它是一种具有副作用的动态语言。除了语法(即使在这方面,Jaskell比Haskell更加笨拙),它与Haskell毫无关系。 - scravy
5
对于那些看到这个讨论的人,需要注意:F#在某些情况下确实需要类型注释:https://dev59.com/EHE85IYBdhLWcg3wLAYV#2977953,而OCaml并不做同样的事情:https://dev59.com/b2Eh5IYBdhLWcg3wVCPK#22533286。 - lcn

24

Scala的类型系统与Haskell的不同,尽管Scala的概念有时直接受到Haskell的优势和其知识渊博的研究员和专业人士社区的启发。

当然,首先在一个不是针对函数式编程的虚拟机上运行会导致与现有语言针对此平台的兼容性问题。由于大部分关于类型的推理都发生在编译时,Java(作为一种语言和平台)在运行时的限制并不值得担心(除了类型擦除,尽管恰恰这个错误似乎使其与Java生态系统的集成更加无缝)。

据我所知,仅在Java的类型系统层面上进行的"妥协"是一种特殊的语法来处理原始类型。虽然Scala甚至不再允许使用原始类型,但它接受具有该错误的旧Java类文件。 也许你已经看到过像List[_](或者更长的等价物List[T] forSome { type T })的代码。这是与Java的兼容性特性,但在内部也被视为存在类型,并且不会削弱类型系统。

Scala的类型系统确实支持类型类,尽管以比Haskell更冗长的方式。我建议阅读这篇论文,它可能会产生不同的印象,关于Scala类型系统的相对优势(第17页上的表格是非常强大的类型系统概念的好列表)。

与类型系统的强大无关的是Scala和Haskell编译器用于推断类型的方法,尽管它对人们编写代码的方式有些影响。 拥有强大的类型推断算法可以使编写更抽象的代码变得更有价值(你可以自己决定在所有情况下是否是一件好事)。

最终,Scala和Haskell的类型系统都是由提供用户解决问题的最佳工具的愿望驱动,但它们已经走上了不同的道路。


3
存在类型并不完全等同于原始类型。例如,List[] 不被认为是另一个 List[] 的相同类型。 - Kevin Wright

13

另一个有趣的观点是,Scala直接支持经典的面向对象风格。这意味着存在子类型关系(例如,List是Seq的子类)。这使得类型推断更加棘手。再加上你可以在Scala中混入特质,这意味着给定类型可以具有多个超类型关系(使它更加棘手)。


10

相关的是,它也不支持非预测性。 - Tom Crockett

8

我对Haskell只有一点经验,但我发现Scala类型系统与Haskell不同的最明显的事情是类型推断。

在Scala中,没有全局类型推断,你必须明确告诉函数参数的类型。

例如,在Scala中,你需要这样写:

def add (x: Int, y: Int) = x + y

替换为
add x y = x + y

这可能会在需要使用可以处理“+”方法的所有类型的通用版本的添加函数时导致问题。虽然有一种解决方法,但它会变得更加冗长。
但在实际使用中,我发现Scala的类型系统足够强大,日常使用几乎不需要使用那些针对通用性的解决方案,可能这是因为我来自Java世界。
而明确声明参数类型的限制并不一定是一件坏事,毕竟你仍然需要记录它。

“需要无论如何记录” - 是的。这就是我对类型推断感到困扰的原因。它似乎都基于错误的信念,即价值在于类型安全,而不是可读性。正如鸭子类型的支持者所指出的那样,在实践中,类型系统捕获的类型错误并不是问题 - 至少在静态类型语言中不是问题。当然,从例如Javascript的角度来看,类型安全似乎很有用,因为存在常量(有效)类型不确定性。但是像nim(以及可能的haskell,我不知道)这样的语言成功地使得一个类型化的语言读起来很像一个鸭子类型的语言。讽刺的是。 - Britton Kerin

6

他们是否可图灵约简?

请参阅Oleg Kiselyov的页面http://okmij.org/ftp/... 可以在Haskell的类型系统中实现λ演算。如果Scala也可以做到这一点,那么从某种意义上说,Haskell的类型系统和Scala的类型系统计算相同的类型。问题是:哪个更自然?哪个更优雅?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接