Haskell的类型系统在形式上是否等同于Java?[关闭]


66

我意识到用一种语言比用另一种语言更容易/更难,但是我只对与类型相关的功能感兴趣,这些功能在一种语言中是可能的而在另一种语言中是不可能/不相关的。为了使它更具体,让我们忽略Haskell类型扩展,因为那里有太多的东西可以处理各种疯狂的事情。


4
我也很奇怪,听到冗长的范畴论者回答了这个问题。尽管我怀疑我会特别理解它,但我仍然对此细节感兴趣。从东西我读过我的倾向是,HM型系统允许编译器知道关于你的代码做了什么这就是为什么它能够推断类型这么多,以及提供有关的行为,使许多担保。但这只是我的直觉,我敢肯定我还没有意识到其他事情。
Jimmy Hoffa 2012年

1
这是一个很大的问题-是时候将其推文发布给关注者,以进行伟大的Haskell / JVM辩论!
Martijn Verburg

6
@ m3th0dman:Scala对高阶函数的支持与Java完全相同。在Scala中,像Java一样,一等函数只是用一个抽象方法简单地表示为抽象类的实例。当然,Scala具有用于定义这些函数的语法糖,并且它具有丰富的标准库,既包含预定义的函数类型,又包含接受函数的方法,但是从类型系统的角度来看,这是关于此问题的内容,没有区别。因此,如果Scala可以做到,那么Java也可以,实际上,有Haskell启发的Java FP库。
约尔格W¯¯米塔格

2
@ m3th0dman:这不是这个问题。
菲尔(Phil)2012年

7
@ m3th0dman它们是完全普通的类型。除了一些语法上的细微之处,列表没有什么特别的。您可以轻松定义自己的与内置列表类型等效的代数数据类型,但字面语法和构造函数的名称除外。
sepp2k 2012年

Answers:


63

(此处使用的“ Java”被定义为标准Java SE 7;此处使用的“ Haskell”被定义为标准Haskell2010。)

Java的类型系统具有但Haskell的不具有:

  • 名义亚型多态性
  • 部分运行时类型信息

Haskell的类型系统具有但Java没有的东西:

  • 有界特设多态性
    • 产生“基于约束的”亚型多态性
  • 更高种类的参数多态性
  • 主要类型

编辑:

上面列出的每个要点的示例:

Java特有的(与Haskell相比)

名义亚型多态性

/* declare explicit subtypes (limited multiple inheritance is allowed) */
abstract class MyList extends AbstractList<String> implements RandomAccess {

    /* specify a type's additional initialization requirements */
    public MyList(elem1: String) {
        super() /* explicit call to a supertype's implementation */
        this.add(elem1) /* might be overridden in a subtype of this type */
    }

}

/* use a type as one of its supertypes (implicit upcasting) */
List<String> l = new ArrayList<>() /* some inference is available for generics */

部分运行时类型信息

/* find the outermost actual type of a value at runtime */
Class<?> c = l.getClass // will be 'java.util.ArrayList'

/* query the relationship between runtime and compile-time types */
Boolean b = l instanceOf MyList // will be 'false'

Haskell独有的(与Java相比)

有界的临时多态性

-- declare a parametrized bound
class A t where
  -- provide a function via this bound
  tInt :: t Int
  -- require other bounds within the functions provided by this bound
  mtInt :: Monad m => m (t Int)
  mtInt = return tInt -- define bound-provided functions via other bound-provided functions

-- fullfill a bound
instance A Maybe where
  tInt = Just 5
  mtInt = return Nothing -- override defaults

-- require exactly the bounds you need (ideally)
tString :: (Functor t, A t) => t String
tString = fmap show tInt -- use bounds that are implied by a concrete type (e.g., "Show Int")

“基于约束的”亚型多态性(基于有限制的即席多态性)

-- declare that a bound implies other bounds (introduce a subbound)
class (A t, Applicative t) => B t where -- bounds don't have to provide functions

-- use multiple bounds (intersection types in the context, union types in the full type)
mtString :: (Monad m, B t) => m (t String)
mtString = return mtInt -- use a bound that is implied by another bound (implicit upcasting)

optString :: Maybe String
optString = join mtString -- full types are contravariant in their contexts

更高种类的参数多态性

-- parametrize types over type variables that are themselves parametrized
data OneOrTwoTs t x = OneVariableT (t x) | TwoFixedTs (t Int) (t String)

-- bounds can be higher-kinded, too
class MonadStrip s where
  -- use arbitrarily nested higher-kinded type variables
  strip :: (Monad m, MonadTrans t) => s t m a -> t m a -> m a

校长打字

很难给出一个直接的例子,但这意味着每个表达式都具有一个最大的通用类型(称为其主体类型),这被认为是该表达式的规范类型。根据“基于约束的”子类型多态性(请参见上文),表达式的主要类型是该表达式可以用作的每种可能类型的唯一子类型。在(未扩展的)Haskell中存在主体类型可以实现完整的类型推断(即,每个表达式都可以成功进行类型推断,而无需任何类型注释)。破坏主体类型(其中有很多)的扩展也破坏了类型推断的完整性。


7
不要使用l作为一个单个字母的变量,它是非常困难的区别1
recursion.ninja 2013年

5
可能值得注意的是,虽然您绝对正确,Java具有一些运行时类型信息,而Haskell没有,但是您可以使用Haskell中的Typeable类型类来提供某些行为,类似于许多类型的运行时类型信息(使用更新的PolyKinded类,它将是所有类型iirc),尽管我认为这取决于情况是否在运行时实际传递任何类型信息。

3
我知道@DarkOtter Typeable,但是Haskell 2010没有它(也许Haskell 2014会吗?)。
Ptharien's Flame 2013年

5
(封闭的)总和类型呢?它们是编码约束的更重要的机制之一。
tibbe

3
空性?健全性(无协方差sillins)?封闭的总和类型/模式匹配?这个答案太狭窄了
Peaker

32

Java的类型系统缺乏更高种类的多态性。Haskell的类型系统拥有它。

换句话说:在Java中,类型构造函数可以在类型上进行抽象,但不能在类型构造函数上进行抽象,而在Haskell中,类型构造函数可以在类型构造函数和类型上进行抽象。

用英语:在Java中,泛型不能接受另一个泛型类型并将其参数化,

public void <Foo> nonsense(Foo<Integer> i, Foo<String> j)

而在Haskell中,这很容易

higherKinded :: Functor f => f Int -> f String
higherKinded = fmap show

28
介意这次再次用英语运行吗?:P
梅森·惠勒2012年

8
@Matt:作为示例,我不能用Java编写此代码,但是可以在Haskell:中编写等效的代码<T<_> extends Collection> T<Integer> convertStringsToInts(T<string> strings)。这里的想法是,如果有人调用它,convertStringsToInts<ArrayList>它将采用字符串数组列表并返回整数数组列表。如果使用convertStringsToInts<LinkedList>,则与链接列表相同。
sepp2k 2012年

8
这不是更高种类的多态性,而不是等级1对n?
亚当

8
@JörgWMittag:我的理解是,更高级别的多态性涉及可以forall在类型中放置的位置。在Haskell中,类型a -> b是隐式的forall a. forall b. a -> b。通过扩展,您可以使它们forall显式并四处移动。
蒂洪·耶维斯

8
@亚当是严厉的:更高的等级和更高的种类完全不同。GHC还可以通过某种语言扩展来执行排名较高的类型(即,所有类型)。Java既不知道更高种类的,也不知道更高等级的类型。
Ingo 2012年

11

为了补充其他答案,Haskell的类型系统没有subtyping,而类型化的面向对象语言就像Java一样。

编程语言理论子类型(也亚型多态性包含多态性)是一种形式的型的多态性,其中,子类型是一个数据类型是与另一数据类型(在超类型)通过一些概念可替代性,这意味着程序元素,典型地子程序编写为在超类型的元素上操作的函数或函数也可以在子类型的元素上操作。如果S是T的子类型,则子类型关系通常写为S <:T,这意味着S类型的任何术语都可以在以下情况下安全使用:T类型的术语是预期的。子类型化的精确语义至关重要地取决于给定编程语言中“在上下文中安全使用”的含义的特殊性。编程语言的类型系统本质上定义了它自己的子类型关系,这可能是微不足道的。

由于子类型关系,一个术语可能属于一种以上的类型。因此,子类型化是类型多态性的一种形式。在面向对象的编程中,术语“多态性”通常仅用于指代该子类型多态性,而参数多态性的技术将被视为通用编程 ...


4
虽然这并不意味着您没有特别的多态性。您只是以另一种形式(类型类而不是子类型多态性)进行操作。

3
子类化不是子类型化!
Frank Shearar

8

到目前为止,没有人提到的一件事是类型推断:Haskell编译器通常可以推断表达式的类型,但是您必须详细告知Java编译器您的类型。严格来说,这是编译器的功能,但是语言和类型系统的设计决定了类型推断是否可行。特别是,类型推断与Java的子类型多态性和临时重载之间存在严重的相互作用。相反,Haskell的设计人员努力不引入影响类型推断的功能。

到目前为止,人们似乎还没有提到的另一件事是代数数据类型。也就是说,具有从其他类型的和(“或”)和乘积(“和”)构造类型的能力。Java类可以很好地完成乘积(例如,字段a和字段b)。但是他们实际上并没有做总和(比如说a或b)。Scala必须将其编码为多个case类,这并不完全相同。尽管它适用于Scala,但要说Java拥有它却有点困难。

Haskell还可以使用函数构造函数->构造函数类型。尽管Java的方法确实具有类型签名,但是您不能将它们组合在一起。

Java的类型系统确实实现了Haskell尚未具备的一种模块化类型。还需要一段时间才能为Haskell提供OSGi。


1
@MattFenwick,我根据您的反馈修改了第三段。这两种类型的系统确实在功能上有很大的不同。
GarethR

我不会将ADT称为类型系统的功能。您可以完全(如果很尴尬)使用OO包装器模拟它们。
大约

@leftaroundabout我认为这可以争论。例如,可能有些东西是一种语言的类型系统固有的,但是可以用另一种语言的设计模式来实现。显然,与本地模式相比,设计模式是一种解决方法。由于类型系统较弱而导致的解决方法。
Hi-Angel

选择的答案在“主要类型”部分提到了“完整类型推断”。Java可以对带有子类型和运行时类型信息的总和进行排序,但是正如您所说的那样,总和不是类型系统的整体属性。
谢尔比·摩尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.