30

にはOCaml、2種類ありequity comparisonsます。

x = yおよびx == y

では、それらの正確な違いは何ですか?

それはJavax = yと同じようにocamlにありますか?x.equals(y)

Javaのx == yように?x == y (comparing the address)

4

4 に答える 4

33

x.equals(y)Javaでどのように機能するのか正確にはわかりません。それが「深い」比較を行う場合、類推はかなり近いです。注意しなければならないことの1つは、物理的な平等はOCaml(および一般的な関数型言語)では滑りやすい概念であるということです。コンパイラとランタイムシステムは値を移動し、純粋な(変更不可能な)値を自由にマージおよびマージ解除できます。==したがって、自分が何をしているかを本当に知っている場合にのみ使用する必要があります。あるレベルでは、実装に精通している必要があります(これは必要な場合を除いて避けるべきものです)。

OCamlが作る特定の保証==は弱いです。変更可能な値は、期待する方法で物理的に等しいと比較されます(つまり、2つの一方を変更すると、もう一方も実際に変更されます)。ただし、不変の値の場合、唯一の保証は、物理的に等しい(==)と比較される値も等しい(=)として比較されることです。sepp2kが浮動値を指摘しているため、逆は真ではないことに注意してください。

本質的に、言語仕様が非可変値について示しているのは==、2つの非可変値が等しいかどうかを判断するためのクイックチェックとして使用できるということです(=)。それらが物理的に等しいと比較した場合、それらは値的に等しいです。それらが物理的に等しいかどうかを比較しない場合、それらが値的に等しいかどうかはわかりません。あなたはまだ=決定するために使用する必要があります。

于 2012-11-27T18:11:39.590 に答える
21

Obj編集:この回答は、モジュールに基づいて、OCamlの内部動作の詳細を掘り下げます。その知識は、特別な注意を払わずに使用することを意図したものではありません(その非常に重要な点をもう一度強調しておきます。プログラムに使用しないでください。ただし、OCamlランタイムを試してみたい場合に限ります)。その情報は、オンラインで入手できるOCamlのO'Reillyの本(少し古いですが、かなり良い本ですが)でおそらくより理解しやすい形で入手することもできます。

=オペレーターは構造的同等性をチェックしていますが、==物理的同等性のみをチェックしています。

同等性チェックは、値がメモリ内に割り当てられて格納される方法に基づいています。OCamlのランタイム値は、ボックス化されたものとボックス化されていないものの2つの異なるカテゴリに大まかに当てはまります。前者は、値が間接参照を介してメモリ内で到達可能であることを意味し、後者は、値に直接アクセスできることを意味します。

int(32ビットシステムではint31、64ビットシステムではint63)はボックス化されていない値であるため、両方の演算子は同じように動作します。ランタイム実装が実際にある他のいくつかのタイプまたは値でも、unit 、空のリスト、代数的データ型の定数、ポリモーフィックバリアントなど、int両方の演算子が同じように動作することがわかります。()[]

リスト、配列、タプル、レコード(C構造体に相当)などの構造体を含むより複雑な値で遊び始めると、これら2つの演算子の違いが明らかになります。構造体内の値は、実行時にネイティブintとして表すことができない限り、ボックス化されます。 (1)。この必要性は、ランタイムシステムが値を処理し、メモリを効率的に管理する方法から生じます。構造化された値は、それ自体が構造化された値である可能性がある他の値から構築されるときに割り当てられます。その場合、参照が使用されます(ボックス化されているため)。

割り当てがあるため、プログラムの異なるポイントでインスタンス化された2つの値が、構造的には等しいものの、物理的に等しい可能性はほとんどありません。各フィールド、または値内の内部要素は、物理的な同一性までは同一である可能性がありますが、これら2つの値が動的に構築されると、メモリ内の異なるスペースを使用することになり、物理的に異なりますが、構造的には等しくなります。 。

ただし、ランタイムは不必要な割り当てを回避しようとします。たとえば、関数が常に同じ値を返す場合(つまり、関数が定数の場合)、単純または構造化されている場合、その関数は常に同じ物理値を返します(つまり、 、メモリ内の同じデータ)、そのため、その関数の2回の呼び出しの結果が物理的に等しいかどうかのテストが成功します。

物理演算子が実際にいつ戻るかを観察する1つの方法は、実行時表現(つまり、その結果)で関数trueを使用することです。この関数は、パラメーターの実行時表現がボックス化されているかどうかを通知するだけです。Obj.is_blockObj.repr

より工夫された方法は、次の関数を使用することです。

let phy x : int = Obj.magic (Obj.repr x);;

この関数は、この値がボックス化されている場合、メモリ内にintバインドされた値へのポインタの実際の値であるを返します。リテラルで試してみると、まったく同じ値が得られます!これは、intがボックス化されていないためです(つまり、値は参照を介さずにメモリに直接格納されます)。xint

ボックス化された値が実際には「参照」値であることがわかったので、言語で不変であると言われていても、これらの値は変更できると推測できます。

たとえば、参照タイプについて考えてみます。

# type 'a ref = {mutable contents : 'a };;

次のように不変の参照を定義できます。

# type 'a imm = {i : 'a };;
type 'a imm = {i : 'a; }

次に、Obj.magic関数を使用して、あるタイプを別のタイプに強制変換します。これは、構造的に、これらのタイプが同じランタイム表現に縮小されるためです。

例えば:

# let x = { i = 1 };;
- : val x : int imm = { i = 1 }
# let y : int ref = Obj.magic x;;
- : val y : int ref = { contents = 1 }
# y := 2;;
- : unit = ()
# x
- : int imm = { i = 2 }

これにはいくつかの例外があります。

  • 値がオブジェクトの場合、一見構造的に同一の値でもfalse構造比較で返されます

    # let o1 = object end;;
    val o1 : < > = <obj>
    # let o2 = object end;;
    val o2 : < > = <obj>
    # o1 = o2;;
    - :  bool = false
    # o1 = o1;;
    - :  bool = true
    

    =ここでは、それが物理的な同等性に戻ることがわかります。

  • 値が関数の場合、構造的に比較することはできませんが、物理的な比較は意図したとおりに機能します。

  • 遅延値は、強制されているかどうかに応じて、構造的に比較できる場合とできない場合があります(それぞれ)。

    # let l1 = lazy (40 + 2);;
    val l1 : lazy_t = <lazy>
    # let l2 = lazy (40 + 2);;
    val l2 : lazy_t = <lazy>
    # l1 = l2;;
    Exception: Invalid_argument "equal: functional value".
    # Lazy.force l1;;
    - :  int = 42
    # Lazy.force l2;;
    - :  int = 42
    # l1 = l2;;
    - :  bool = true 
    
  • モジュール値またはレコード値も、機能値が含まれていない場合は比較可能です。

一般に、関数に関連する値、または関数を内部に保持する可能性のある値は、と比較することはできませんが=、と比較することはできます==

明らかに、これらすべてに非常に注意する必要があります。ランタイムの実装の詳細に依存することは正しくありません(注:その回答の最初のバージョンでという言葉を冗談めかして使用しましたが、あまりにも真剣に受け止められることを恐れて変更しました)。コメントで適切に指摘されているように、javascript実装の動作はfloatでは異なります(javascriptでは構造的に同等ですが、リファレンス実装ではそうではありません。javaの実装はどうですか?)。


(1)正しく思い出せば、二重間接参照を避けるために、floatは配列に格納されるときにもボックス化されませんが、抽出されるとボックス化されるため、ボックス化された値との動作の違いはわかりません。

于 2012-11-28T01:20:54.877 に答える
9

それはJavaのx.equals(y)と同じようにocamlのx = yですか?

そして、Javaのx == y(アドレスの比較)と同じようにx == y?

はい、それだけです。ただし、OCamlではあらゆる種類の値で使用できますが、Javaではプリミティブ型で=は使用できません。equalsもう1つの違いは、OCamlの浮動小数点数は参照型であるため、を使用してそれらを比較するべきでは==ないということです(とにかく、浮動小数点数を直接比較することは一般的に良い考えではありません)。

したがって、要約すると、基本的には、=あらゆる種類の値を比較するために常に使用する必要があります。

于 2012-11-27T18:06:41.290 に答える
2

http://rigaux.org/language-study/syntax-across-languages-per-language/OCaml.htmlによると==、浅い平等を=チェックし、深い平等をチェックします

于 2012-11-27T18:07:13.340 に答える