ある言語では他の言語よりも簡単/難しいこともありますが、興味があるのは、ある言語では可能で、別の言語では不可能/無関係なタイプ関連の機能だけです。より具体的にするために、Haskell型の拡張機能を無視しましょう。あらゆる種類のクレイジー/クールなことを行うものが非常に多くあるからです。
ある言語では他の言語よりも簡単/難しいこともありますが、興味があるのは、ある言語では可能で、別の言語では不可能/無関係なタイプ関連の機能だけです。より具体的にするために、Haskell型の拡張機能を無視しましょう。あらゆる種類のクレイジー/クールなことを行うものが非常に多くあるからです。
回答:
(ここで使用される「Java」は標準Java SE 7として定義され、ここで使用される「Haskell」は標準Haskell 2010として定義されます。)
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つの最大一般型(そのプリンシパル型と呼ばれる)が1つだけあることを意味します。「制約ベース」のサブタイプ多型(上記参照)に関して、式の主要なタイプは、その式を使用できるすべての可能なタイプの一意のサブタイプです。(拡張されていない)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の型システムにはサブタイプがありませんが、Javaのように型指定されたオブジェクト指向言語です。
でプログラミング言語理論、サブタイピングは、(また、多型サブタイプ又は封入多型の形態である)型の多型ているサブタイプがあるデータ型の別のデータ型(に関連するスーパータイプのいくつかの概念による)代替典型的サブルーチン、そのプログラム要素を意味し、または、スーパータイプの要素を操作するように記述された関数は、サブタイプの要素も操作できます。SがTのサブタイプである場合、サブタイプ関係はS <:Tで記述されることが多く、タイプSのどの用語もコンテキストで安全に使用できることを意味します。タイプTの用語が予想されます。サブタイピングの正確なセマンティクスは、特定のプログラミング言語で「コンテキストで安全に使用される場所」の意味に大きく依存します。プログラミング言語の型システムは、基本的に独自のサブタイピング関係を定義します。
サブタイプ関係により、用語は複数のタイプに属する場合があります。したがって、サブタイピングは型多型の一種です。オブジェクト指向プログラミングでは、「ポリモーフィズム」という用語は一般にこのサブタイプポリモーフィズムのみを指すために使用されますが、パラメトリックポリモーフィズムの技術は一般的なプログラミングと見なされます ...
これまで誰も言及していないことの1つは型推論です。Haskellコンパイラは通常式の型を推論できますが、Javaコンパイラに型を詳細に伝える必要があります。厳密には、これはコンパイラの機能ですが、言語と型システムの設計により型推論が実行可能かどうかが決まります。特に、型推論は、Javaのサブタイプ多型およびアドホックなオーバーロードと相互作用します。対照的に、Haskellの設計者は、型推論に影響を与える機能を導入しないように努力しています。
他の人がこれまで言及していないように見えることは、代数的データ型です。つまり、他の型の合計(「または」)および積(「および」)から型を構築する機能です。Javaクラスは、製品(フィールドaおよびフィールドb、たとえば)を正常に実行します。ただし、実際には合計を行いません(フィールドaまたはフィールドb、たとえば)。Scalaはこれを複数のケースクラスとしてエンコードする必要がありますが、これはまったく同じではありません。また、Scalaでも機能しますが、Javaにそれがあると言うのは少しばかりです。
Haskellは、関数コンストラクタ->を使用して関数型を構築することもできます。Javaのメソッドには型シグネチャがありますが、それらを組み合わせることはできません。
Javaの型システムは、Haskellにはないタイプのモジュール性を可能にします。Haskell用のOSGiが登場するまでにはしばらく時間がかかります。