web-dev-qa-db-ja.com

HaskellのundefinedとJavaのnullの違いは何ですか?

どちらも、タイプがすべてのタイプの共通部分(無人)である用語です。どちらも、評価を試みるまで失敗することなくコードで渡すことができます。私が見ることができる唯一の違いは、Javaには、nullを正確に1つの操作、つまり参照の同等性の比較(==)-一方、Haskellではundefinedは例外をスローせずに評価することはできません。これが唯一の違いですか?

編集

私がこの質問で本当に得ようとしているのは、なぜnullをJavaのような明らかに悪い決定に含めたのか、そしてHaskellはそれをどのように回避するのか?本当の問題は、nullで何か便利を実行できることです。つまり、nullnessをチェックできます。コードでnull値を渡し、「このプログラムに論理エラーがあります」ではなく「結果なし」を示すことが標準的な規則になっています。一方、Haskellでは、評価せずに用語が最下位に評価されるかどうかを確認する方法はありません。それとプログラムが爆発するので、「結果なし」を示すような方法で使用することはできません。代わりに、Maybeのようなものを使用する必要があります。

「評価する」という言葉で速くて緩いプレーをしているように思われる場合は申し訳ありません...ここでアナロジーを表現しようとしていますが、正確に表現するのに苦労しています。これは、類推が不正確であることを示していると思います。

51
Tom Crockett

HaskellのundefinedとJavaのnullの違いは何ですか?

さて、少しバックアップしましょう。

Haskellの「undefined」は「bottom」値の例です(⊥で示されています)。このような値は、プログラム内の未定義、スタック、または部分的な状態を表します。

ボトムにはさまざまな形式があります。非終了ループ、例外、パターンマッチの失敗など、基本的に、ある意味で定義されていないプログラム内の状態です。値_undefined :: a_は、プログラムを未定義の状態にする値の標準的な例です。

undefined自体は特に特別なものではなく、配線されていません。Haskellのundefinedは、任意のボトムイールド式を使用して実装できます。例えば。これはundefinedの有効な実装です。

_ > undefined = undefined
_

または、すぐに終了します(古いGoferコンパイラはこの定義を使用していました):

_ > undefined | False = undefined
_

Bottomの主な特性は、式がbottomに評価される場合、プログラム全体がbottomに評価されることです。プログラムは未定義の状態にあります。

なぜあなたはそのような価値が欲しいのですか?まあ、怠惰な言語では、プログラム自体がボトムでなくても、ボトム値を格納する構造や関数を操作できることがよくあります。

例えば。無限ループのリストは完全に混雑しています:

_ > let xs = [ let f = f in f 
            , let g n = g (n+1) in g 0
            ]
 > :t xs
 xs :: [t]
 > length xs
 2
_

私はリストの要素で多くをすることができません:

_ > head xs
 ^CInterrupted.
_

この無限のものの操作は、ハスケルがとても楽しく表現力豊かな理由の一部です。怠惰の結果、Haskellはbottom値に特に細心の注意を払っています。

ただし、明らかに、ボトムの概念はJavaやその他の(合計ではない)言語にも同様に当てはまります。 Javaには、「ボトム」値を生成する多くの式があります。

  • 参照をnullと比較します(ただし、明確に定義されているnull自体ではありません)。
  • ゼロ除算。
  • 範囲外の例外。
  • 無限ループなど。

あるボトムを別のボトムに簡単に置き換えることができないだけで、Javaコンパイラはボトム値について推論することはあまりありません。しかし、そのような値はあります。

要約すれば、

  • Javaでnull値を逆参照することは、Javaで最下位の値を生成する1つの特定の式です。
  • haskellのundefined値は、Haskellでボトム値が必要な場所ならどこでも使用できる一般的なボトムイールド式です。

それが彼らが似ている方法です。

追記

null自体の質問に関して:なぜそれが悪い形式と見なされるのですか?

  • まず、Javaのnullは本質的にHaskellのすべてのタイプaに暗黙の_Maybe a_を追加すると同等です。
  • nullの逆参照は、Justの場合のみのパターンマッチングと同等です:f (Just a) = ... a ...

したがって、渡される値がNothing(Haskellの場合)またはnull(Javaの場合)の場合、プログラムは未定義の状態になります。これは悪いことです:あなたのプログラムはクラッシュします。

したがって、everyタイプにnullを追加することで、bottom値の作成がはるかに簡単になりました。事故-タイプはもはやあなたを助けません。あなたの言語はもはやその特定の種類のエラーを防ぐのに役立っていません、そしてそれは悪いことです。

もちろん、他のボトム値もまだあります:例外(undefinedなど)、または無限ループ。すべての関数に新しい可能性のある失敗モードを追加する(nullを逆参照する)と、クラッシュするプログラムを簡単に作成できるようになります。

72
Don Stewart

あなたの説明は完全に正しくありません。 nullは評価できないと言っています。ただし、Javaは熱心な言語であるため、これは、fの定義が何であっても、f(null)がNPEをスローすることを意味します(メソッド引数はメソッドが実行される前に常に評価されます)。

例外を取得せずにhaskellでundefinedを渡すことができる唯一の理由は、haskellが怠惰であり、必要な場合を除いて引数を評価しないことです。

Undefinedとnullのもう1つの違いは、undefinedが標準ライブラリで定義されている単純な値であることです。標準ライブラリで定義されていない場合は、自分で定義できます(たとえば、_myUndefined = error "My Undefined_と記述します)。

In Java nullはキーワードです。nullキーワードがない場合、それを定義することはできません(haskellの定義と同等のことを行います)。 、つまりObject myNull = throw(new Exception())は、式がその場で評価されるため、機能しません)。

7
sepp2k