ある言語では他の言語よりも簡単で難しいものがあることに気づきましたが、興味があるのは、一方では可能であり、もう一方では不可能/無関係なタイプ関連の機能のみです。より具体的にするために、Haskellの型拡張機能は無視してみましょう。非常に多くのクレイジーでクールな機能を実行するものがたくさんあるからです。
(ここで使用されている「Java」は standard Java SE 7 として定義されています。ここで使用されている「Haskell」は standard Haskell 201 。)
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
これは、直接的な例を示すのは難しいですが、すべての式が厳密に1つの最大汎用型(そのプリンシパル型と呼ばれる)を持っていることを意味し、その正規型と見なされます式。 「制約ベース」のサブタイプの多型性(上記を参照)に関して、式の主要なタイプは、その式を使用できるすべての可能なタイプの一意のサブタイプです。 (拡張されていない)Haskellでのプリンシパル型の存在は、完全な型推論(つまり、型注釈を必要とせずに、すべての式の型推論の成功)を可能にするものです。プリンシパルタイピング(多くあります)を壊す拡張機能も、タイプ推論の完全性を壊します。
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
他の答えを補足するために、Haskellの型システムには subtyping がありませんが、型付きオブジェクト指向言語にはJavaはあります。
プログラミング言語理論 、subtyping(alsosubtype polymorphismまたは包含ポリモーフィズム)は type polymorphism の形式であり、ここで subtypeは datatype であり、別のデータ型(supertype)に関連しています substitutability の概念。つまり、スーパータイプの要素を操作するように記述されたプログラム要素(通常はサブルーチンまたは関数)も、サブタイプの要素を操作できることを意味します。 SがTのサブタイプである場合、サブタイピング関係はしばしばS <:Tと書かれます。これは、タイプSの任意の項が安全に使用できるコンテキストタイプTが必要です。サブタイピングの正確なセマンティクスは、特定のプログラミング言語で「どこで安全に使用されるか」が何を意味するかの詳細に大きく依存します。プログラミング言語の type system は、本質的に独自のサブタイプ関係を定義します。
サブタイプの関係により、用語は複数のタイプに属する場合があります。したがって、サブタイピングはタイプの多型の一種です。オブジェクト指向プログラミングでは、「ポリモーフィズム」という用語は、このサブタイプポリモーフィズムのみを指すのに一般的に使用されますが、パラメトリックポリモーフィズムの手法は考慮されます 一般的なプログラミング ...
これまで誰も言及していないことの1つは型推論です。Haskellコンパイラは通常、式の型を推論できますが、Javaコンパイラに型を詳細に通知する必要があります。厳密に、これはコンパイラですが、言語と型システムの設計により、型推論が実行可能かどうかが決定されます。特に、型推論はJavaのサブタイプポリモーフィズムやアドホックオーバーロードとうまく相互作用しません。対照的に、Haskellの設計者は、型推論に影響を与える機能を導入しないように努めています。
これまで人々が言及しなかったように思われるもう1つのことは、代数的データ型です。つまり、他のタイプの合計(「または」)および積(「および」)からタイプを構成する機能です。 Javaクラスは製品(フィールドaとフィールドbなど)を正常に実行しますが、実際には合計を実行しません(フィールドa ORフィールドbなど)) 。Scalaは、これを複数のケースクラスとしてエンコードする必要がありますが、これはまったく同じではありません。また、Scalaに対しては機能しますが、 Javaはそれを持っています。
Haskellは、関数コンストラクター->を使用して関数型を構築することもできます。 Javaのメソッドには型シグニチャーがありますが、それらを組み合わせることはできません。
Javaの型システムは、Haskellが持っていないmodularityの型を有効にします。 Haskell用のOSGiが登場するまでにはしばらくかかるでしょう。