2011-06-29 13 views
4

のは、私が同じコンストラクタで2つの値が作成されているかどうかをチェックする方法は?

type t = A of int | B of int 

let xx = A(2);; 
let yy = A(3);; 

を持っていると私はXXとYYのコンストラクタが等しいかどうかをテストしたいとしましょう、 はこれを行う簡単な方法は何ですか?

match xx, yy with 
| A _, A _ 
| B _, B _ -> true 
| (A _ | B _), _ -> false 

が、私は認識していないよ。その代わり、やや単純、上記にタイプであり、多くのコンストラクタは

答えて

7

あなたは書き換えることができたときにはかなり厄介取得

match xx with 
    A _ -> 
    (match yy with A _ -> true | B _ -> false) 
| B _ -> 
    (match yy with A _ -> false | B _ -> true);; 

を有するのすべてのコンストラクタを列挙しないソリューション

+3

これは間違いありませんが、 '_、_'や '(A _ | B _)、_ 'の使用を避ける方が賢明です。このようにして、コンストラクターが変更された場合、コンパイラーはエラーを見つけるのに役立ちます。これについての議論があります。http://stackoverflow.com/questions/4346901/suggestion-for-solving-fragile-pattern-matching – nlucaroni

+1

これは、値のタグを比較することによって行うことができます(適切な型の注釈では安全です)。 – ygrek

+0

@niucaroni:確かに、非常に良い点。私は答えにそれを組み込むために自由を取った。 – akoprowski

5

これは、モジュールのObjによって可能です。 Obj関数を使ってオブジェクトを解析すると、正しく実行されてもプログラムはクラッシュしません。意味のある結果を得るためには注意が必要です。二つの値が同じゼロ引数のコンストラクタを持っている場合、バリアント型(ない多型バリアント型)の値に呼び出さ

let equal_constructors (x : 'a) (y : 'a) = 
    let r = Obj.repr x and s = Obj.repr y in 
    if Obj.is_int r && Obj.is_int s then (Obj.obj r : int) = (Obj.obj s : int) else 
    if Obj.is_block r && Obj.is_block s then Obj.tag r = Obj.tag s else 
    false 

は、この関数はtrueを返すまたは両方が同じ有する1又は-more-それ以外の場合はfalseです。タイプシステムは、他のタイプでequal_constructorsをインスタンス化するのを妨げません。 trueまたはfalseの戻り値が得られますが、必ずしも意味があるとは限りません。

+0

これは幾分醜い低レベルのハックであり、コンパイラの実装の詳細に非常に依存しています。以下の解決策が望ましい。 – yzzlr

+3

@yzzlr Cインタフェースの仕様は、自分のコードが依存する表現プロパティを保証します。だから、それは醜い低レベルのハックですが、それが依存しているのは、(唯一の)実装の文書化された動作の一部です。 – Gilles

4

これを行うもう1つの方法は、タグに対応する別のタイプを作成し、そのタイプを使用することです。

type t = A of int | B of int 
module Tag = struct type t = A | B end 

let to_tag = function A _ -> Tag.A | B _ -> Tag.B 
let tags_are_equal x y = 
    to_tag x = to_tag y 
関連する問題