どちらも、タイプがすべてのタイプの共通部分(無人)である用語です。どちらも、評価を試みるまで失敗することなくコードで渡すことができます。私が見ることができる唯一の違いは、Javaには、null
を正確に1つの操作、つまり参照の同等性の比較(==
)-一方、Haskellではundefined
は例外をスローせずに評価することはできません。これが唯一の違いですか?
私がこの質問で本当に得ようとしているのは、なぜnull
をJavaのような明らかに悪い決定に含めたのか、そしてHaskellはそれをどのように回避するのか?本当の問題は、null
で何か便利を実行できることです。つまり、nullnessをチェックできます。コードでnull値を渡し、「このプログラムに論理エラーがあります」ではなく「結果なし」を示すことが標準的な規則になっています。一方、Haskellでは、評価せずに用語が最下位に評価されるかどうかを確認する方法はありません。それとプログラムが爆発するので、「結果なし」を示すような方法で使用することはできません。代わりに、Maybe
のようなものを使用する必要があります。
「評価する」という言葉で速くて緩いプレーをしているように思われる場合は申し訳ありません...ここでアナロジーを表現しようとしていますが、正確に表現するのに苦労しています。これは、類推が不正確であることを示していると思います。
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
自体ではありません)。あるボトムを別のボトムに簡単に置き換えることができないだけで、Javaコンパイラはボトム値について推論することはあまりありません。しかし、そのような値はあります。
要約すれば、
null
値を逆参照することは、Javaで最下位の値を生成する1つの特定の式です。undefined
値は、Haskellでボトム値が必要な場所ならどこでも使用できる一般的なボトムイールド式です。それが彼らが似ている方法です。
追記
null
自体の質問に関して:なぜそれが悪い形式と見なされるのですか?
null
は本質的にHaskellのすべてのタイプa
に暗黙の_Maybe a
_を追加すると同等です。null
の逆参照は、Just
の場合のみのパターンマッチングと同等です:f (Just a) = ... a ...
したがって、渡される値がNothing
(Haskellの場合)またはnull
(Javaの場合)の場合、プログラムは未定義の状態になります。これは悪いことです:あなたのプログラムはクラッシュします。
したがって、everyタイプにnull
を追加することで、bottom
値の作成がはるかに簡単になりました。事故-タイプはもはやあなたを助けません。あなたの言語はもはやその特定の種類のエラーを防ぐのに役立っていません、そしてそれは悪いことです。
もちろん、他のボトム値もまだあります:例外(undefined
など)、または無限ループ。すべての関数に新しい可能性のある失敗モードを追加する(null
を逆参照する)と、クラッシュするプログラムを簡単に作成できるようになります。
あなたの説明は完全に正しくありません。 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())
は、式がその場で評価されるため、機能しません)。