我意识到用一种语言比用另一种语言更容易/更难,但是我只对与类型相关的功能感兴趣,这些功能在一种语言中是可能的而在另一种语言中是不可能/不相关的。为了使它更具体,让我们忽略Haskell类型扩展,因为那里有太多的东西可以处理各种疯狂的事情。
我意识到用一种语言比用另一种语言更容易/更难,但是我只对与类型相关的功能感兴趣,这些功能在一种语言中是可能的而在另一种语言中是不可能/不相关的。为了使它更具体,让我们忽略Haskell类型扩展,因为那里有太多的东西可以处理各种疯狂的事情。
Answers:
(此处使用的“ Java”被定义为标准Java SE 7;此处使用的“ Haskell”被定义为标准Haskell2010。)
Java的类型系统具有但Haskell的不具有:
Haskell的类型系统具有但Java没有的东西:
编辑:
上面列出的每个要点的示例:
/* 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'
-- 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中存在主体类型可以实现完整的类型推断(即,每个表达式都可以成功进行类型推断,而无需任何类型注释)。破坏主体类型(其中有很多)的扩展也破坏了类型推断的完整性。
l
作为一个单个字母的变量,它是非常困难的区别1
!
Typeable
,但是Haskell 2010没有它(也许Haskell 2014会吗?)。
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
<T<_> extends Collection> T<Integer> convertStringsToInts(T<string> strings)
。这里的想法是,如果有人调用它,convertStringsToInts<ArrayList>
它将采用字符串数组列表并返回整数数组列表。如果使用convertStringsToInts<LinkedList>
,则与链接列表相同。
forall
在类型中放置的位置。在Haskell中,类型a -> b
是隐式的forall a. forall b. a -> b
。通过扩展,您可以使它们forall
显式并四处移动。
为了补充其他答案,Haskell的类型系统没有subtyping,而类型化的面向对象语言就像Java一样。
在编程语言理论,子类型(也亚型多态性或包含多态性)是一种形式的型的多态性,其中,子类型是一个数据类型是与另一数据类型(在超类型)通过一些概念可替代性,这意味着程序元素,典型地子程序编写为在超类型的元素上操作的函数或函数也可以在子类型的元素上操作。如果S是T的子类型,则子类型关系通常写为S <:T,这意味着S类型的任何术语都可以在以下情况下安全使用:T类型的术语是预期的。子类型化的精确语义至关重要地取决于给定编程语言中“在上下文中安全使用”的含义的特殊性。编程语言的类型系统本质上定义了它自己的子类型关系,这可能是微不足道的。
由于子类型关系,一个术语可能属于一种以上的类型。因此,子类型化是类型多态性的一种形式。在面向对象的编程中,术语“多态性”通常仅用于指代该子类型多态性,而参数多态性的技术将被视为通用编程 ...
到目前为止,没有人提到的一件事是类型推断:Haskell编译器通常可以推断表达式的类型,但是您必须详细告知Java编译器您的类型。严格来说,这是编译器的功能,但是语言和类型系统的设计决定了类型推断是否可行。特别是,类型推断与Java的子类型多态性和临时重载之间存在严重的相互作用。相反,Haskell的设计人员努力不引入影响类型推断的功能。
到目前为止,人们似乎还没有提到的另一件事是代数数据类型。也就是说,具有从其他类型的和(“或”)和乘积(“和”)构造类型的能力。Java类可以很好地完成乘积(例如,字段a和字段b)。但是他们实际上并没有做总和(比如说a或b)。Scala必须将其编码为多个case类,这并不完全相同。尽管它适用于Scala,但要说Java拥有它却有点困难。
Haskell还可以使用函数构造函数->构造函数类型。尽管Java的方法确实具有类型签名,但是您不能将它们组合在一起。
Java的类型系统确实实现了Haskell尚未具备的一种模块化类型。还需要一段时间才能为Haskell提供OSGi。