Haskellの型システムはJavaの型システムと形式的に同等ですか?[閉まっている]


66

ある言語では他の言語よりも簡単/難しいこともありますが、興味があるのは、ある言語では可能で、別の言語では不可能/無関係なタイプ関連の機能だけです。より具体的にするために、Haskell型の拡張機能を無視しましょう。あらゆる種類のクレイジー/クールなことを行うものが非常に多くあるからです。


4
私も、この問いに対する長いカテゴリーの理論家の回答を聞きたいと思っています。特に理解できるとは思わないが、私はまだこの詳細に興味がある。私が読んだものから、私の傾斜は、HM型システムは、コンパイラが知ることができることですトンあなたのコードは、それが種類を推定するので、多くの同様の挙動に関する非常に多くの保証を与えることが可能な理由である何をするかについてを。しかし、それはただの本能であり、私はまったく気づいていない他のことがあると確信しています。
ジミー・ホッファ

1
これは素晴らしい質問です-素晴らしいHaskell / JVM討論のためにフォロワーにツイートする時です!
マルタインVerburg

6
@ m3th0dman:Scalaは、Javaと同様に高階関数を完全にサポートしています。Scalaでは、ファーストクラスの関数は、Javaのように、1つの抽象メソッドを持つ抽象クラスのインスタンスとして単純に表されます。確かに、Scalaにはこれらの関数を定義するための構文糖衣があり、関数を受け入れる定義済みの関数型とメソッドの両方の豊富な標準ライブラリがありますが、型システムの観点からは、この質問の目的は違いはありません。そのため、Scalaでできるなら、Javaでもできます。実際、Java用のHaskellにヒントを得たFPライブラリがあります。
ヨルグWミットタグ

2
@ m3th0dman:それはこの質問の目的ではありません。
フィル

7
@ m3th0dmanこれらは完全に普通の型です。リストには特別なものはありませんが、いくつかの相乗効果があります。リテラル構文とコンストラクターの名前を除き、組み込みリスト型と同等の独自の代数データ型を簡単に定義できます。
sepp2k

回答:


63

(ここで使用される「Java」は標準Java SE 7として定義され、ここで使用される「Haskell」は標準Haskell 2010として定義されます。)

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

プリンシパルタイピング

これを直接例証することは困難ですが、すべての式には、その式の標準型と見なされる最大1つの最大一般型(そのプリンシパル型と呼ばれる)が1つだけあることを意味します。「制約ベース」のサブタイプ多型(上記参照)に関して、式の主要なタイプは、その式を使用できるすべての可能なタイプの一意のサブタイプです。(拡張されていない)Haskellのプリンシパルタイピングの存在は、完全な型推論(つまり、型注釈を必要とせずに、すべての式の型推論が成功する)を可能にします。プリンシパルタイピング(その多くが存在する)を壊す拡張機能は、型推論の完全性も壊します。


7
使用しないでくださいl単一の文字変数として非常に区別するのは難しいです1
recursion.ninja

5
Javaには実行時型情報があり、Haskellにはないことは絶対に正しいのですが、HaskellのTypeable型クラスを使用して、多くの型の実行時型情報のように動作するものを提供できることに注意してください(新しいPolyKinded途中のクラスでは、すべての型(iirc)になりますが、実行時に型情報を実際に渡すかどうかは状況に依存すると思いますが

3
@DarkOtter知っていますがTypeable、Haskell 2010にはありません(おそらくHaskell 2014にありますか?)。
プサリアンの炎

5
(閉じた)合計タイプはどうですか?これらは、エンコーディング制約のより重要なメカニズムの1つです。
tibbe

3
Nullability?健全性(共分散シリンスなし)?クローズドサムタイプ/パターンマッチ?この答えは幅が狭すぎる
-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
メイソンウィーラー

8
@Matt:例として、私はJavaでこれを書くことはできませんが、Haskell:で同等のものを書くことができます<T<_> extends Collection> T<Integer> convertStringsToInts(T<string> strings)。ここでのアイデアは、誰かがそれをconvertStringsToInts<ArrayList>呼び出すと、文字列の配列リストを取り、整数の配列リストを返すということです。そして、代わりにを使用した場合、代わりにconvertStringsToInts<LinkedList>リンクリストと同じになります。
sepp2k

8
ランク1対nではなく、この高次の多型ではないでしょうか?
アダム

8
@JörgWMittag:私の理解では、上位のポリモーフィズムは型をどこに置くことができるかということforallです。Haskellでは、型a -> bは暗黙的にforall a. forall b. a -> bです。拡張機能を使用すると、これらをforall明示的に指定して移動できます。
ティコンジャービス

8
@Adamは厳密です。上位ランクと上位ランクはまったく異なります。GHCは、いくつかの言語拡張を使用して、より高いランクのタイプ(つまり、すべてのタイプ)を実行することもできます。Javaは、より高い種類とより高いランクの種類を認識しません。
インゴ

11

他の答えを補完するために、Haskellの型システムにはサブタイプがありませんが、Javaのように型指定されたオブジェクト指向言語です。

プログラミング言語理論サブタイピングは、(また、多型サブタイプ又は封入多型の形態である)型の多型ているサブタイプがあるデータ型の別のデータ型(に関連するスーパータイプのいくつかの概念による)代替典型的サブルーチン、そのプログラム要素を意味し、または、スーパータイプの要素を操作するように記述された関数は、サブタイプの要素も操作できます。SがTのサブタイプである場合、サブタイプ関係はS <:Tで記述されることが多く、タイプSのどの用語もコンテキストで安全に使用できることを意味します。タイプTの用語が予想されます。サブタイピングの正確なセマンティクスは、特定のプログラミング言語で「コンテキストで安全に使用される場所」の意味に大きく依存します。プログラミング言語の型システムは、基本的に独自のサブタイピング関係を定義します。

サブタイプ関係により、用語は複数のタイプに属する場合があります。したがって、サブタイピングは型多型の一種です。オブジェクト指向プログラミングでは、「ポリモーフィズム」という用語は一般にこのサブタイプポリモーフィズムのみを指すために使用されますが、パラメトリックポリモーフィズムの技術は一般的なプログラミングと見なされます ...


4
ただし、アドホックなポリモーフィズムが発生しないわけではありません。別の形式(サブタイプ多型ではなくタイプクラス)で行います。

3
サブクラス化はサブタイプ化ではありません!
フランクシェラー

8

これまで誰も言及していないことの1つは型推論です。Haskellコンパイラは通常式の型を推論できますが、Javaコンパイラに型を詳細に伝える必要があります。厳密には、これはコンパイラの機能ですが、言語と型システムの設計により型推論が実行可能かどうかが決まります。特に、型推論は、Javaのサブタイプ多型およびアドホックなオーバーロードと相互作用します。対照的に、Haskellの設計者は、型推論に影響を与える機能を導入しないように努力しています。

他の人がこれまで言及していないように見えることは、代数的データ型です。つまり、他の型の合計(「または」)および積(「および」)から型を構築する機能です。Javaクラスは、製品(フィールドaおよびフィールドb、たとえば)を正常に実行します。ただし、実際には合計を行いません(フィールドaまたはフィールドb、たとえば)。Scalaはこれを複数のケースクラスとしてエンコードする必要がありますが、これはまったく同じではありません。また、Scalaでも機能しますが、Javaにそれがあると言うのは少しばかりです。

Haskellは、関数コンストラクタ->を使用して関数型を構築することもできます。Javaのメソッドには型シグネチャがありますが、それらを組み合わせることはできません。

Javaの型システムは、Haskellにはないタイプのモジュール性を可能にします。Haskell用のOSGiが登場するまでにはしばらく時間がかかります。


1
@MattFenwick、私はあなたのフィードバックに基づいて3番目の段落を修正しました。2つのタイプのシステムは、機能を非常に異なって扱います。
GarethR

ADTを型システムの機能とは呼びません。OOラッパーでそれらを完全に(厄介な場合)エミュレートできます。
左辺約14年

@leftaroundaboutこれはほぼ間違いないと思います。たとえば、ある言語の型システムにはネイティブであるが、別の言語のデザインパターンで実装できるものがあります。明らかに、設計パターンの方法は、ネイティブの方法と比較して、回避策です。型システムが弱いための回避策。
ハイエンジェル

選択された回答は、「プリンシパルタイピング」セクションで「完全な型推論」に言及しています。Javaは、サブタイプとランタイムタイプ情報を使用して合計をエミュレートできますが、ご指摘のとおり、合計はタイプシステムの全体的な属性ではありません。
シェルビームーアIII
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.