问题
let's say I have
type t = A of int | B of int
let xx = A(2);;
let yy = A(3);;
and I want to test if the constructors of xx and yy are equal, is there an easy way to do this ? Instead of having to
match xx with
A _ ->
(match yy with A _ -> true | B _ -> false)
| B _ ->
(match yy with A _ -> false | B _ -> true);;
which gets quite messy when there many constructors on a type
回答1:
You can rewrite the above to, somewhat simpler:
match xx, yy with
| A _, A _
| B _, B _ -> true
| (A _ | B _), _ -> false
but I'm not aware of a solution without enumerating all the constructors.
回答2:
This is possible, sort of, through the Obj
module. Analyzing objects through the Obj
functions, if done properly, won't crash your program; but you need to be careful if you want to get meaningful results.
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
When called on values of a variant type (not a polymorphic variant type), this function returns true
if the two values both have the same zero-argument constructor or both have the same 1-or-more-argument constructor, and false
otherwise. The type system won't prevent you from instanciating equal_constructors
at other types; you'll get a true
or false
return value but not necessarily a meaningful one.
回答3:
Another way of doing this that can work well is to create another type that corresponds to the tags, and use that type.
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
来源:https://stackoverflow.com/questions/6522360/how-to-check-whether-two-values-are-created-with-the-same-constructor