52

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

編集

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

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

4

2 に答える 2

75

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

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

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

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

undefinedそれ自体は特に特別なものではなく、配線されていません。またundefined、ボトムイールド式を使用してHaskellを実装できます。たとえば、これは次の有効な実装です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がとても楽しく表現力豊かな理由の一部です。怠惰の結果、Haskellは特に価値観に細心の注意を払っていbottomます。

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

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

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

要約すれば、

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

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

追記

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

  • まず、Javaは、Haskellのすべての型に暗黙を追加することnullと本質的に同等です。Maybe aa
  • 間接参照は、次の場合nullにのみパターンマッチングと同等です。Justf (Just a) = ... a ...

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

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

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

于 2010-10-18T21:15:17.243 に答える
7

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

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

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

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

于 2010-10-18T20:13:20.567 に答える