-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
deriving different equality functions for the same type #249
Comments
Several half-baked ideas:
|
Thanks @gasche! I'll ruminate this. The trick using a ref (2) is probably the simplest and could be made foolproof by setting a flag that indicates whether a comparison is in progress. Something like this: type busy_with_equal = Not_busy | Structural_equal | Referential_equal
let busy_with_equal = ref Not_busy
let equal_id a b =
match !busy_with_equal with
| Not_busy -> assert false
| Structural_equal -> true
| Referential_equal -> a = b
let equal_stmt_value_ref = ref (fun a b -> failwith "not initialized")
let equal_value a b =
match !busy_with_equal with
| Not_busy -> assert false
| Structural_equal -> !equal_stmt_value_ref a b
| Referential_equal -> true
type stmt = {
id : int [@equal equal_id];
value : stmt_value [@equal equal_value];
}
and expr = ...
...
let () = equal_stmt_value_ref := equal_stmt_value
let with_structural_equal equal a b =
Fun.protect
~finally:(fun () -> busy_with_equal := Not_busy)
(fun () ->
match !busy_with_equal with
| Not_busy ->
busy_with_equal := Structural_equal;
equal a b
| Structural_equal
| Referential_equal ->
failwith "an equal is already in progress"
)
let with_referential_equal equal a b =
Fun.protect
~finally:(fun () -> busy_with_equal := Not_busy)
(fun () ->
match !busy_with_equal with
| Not_busy ->
busy_with_equal := Referential_equal;
equal a b
| Structural_equal
| Referential_equal ->
failwith "an equal is already in progress"
) |
I think there is a minor bug in your code: if you |
nice catch, thank you. For the record, this is the corrected code (still untested): let with_structural_equal equal a b =
match !busy_with_equal with
| Not_busy ->
busy_with_equal := Structural_equal;
Fun.protect
~finally:(fun () -> busy_with_equal := Not_busy)
(fun () -> equal a b)
| Structural_equal
| Referential_equal ->
failwith "an equal is already in progress"
(* + similar fix for with_referential_equal *) |
Also, the following doesn't work (type let equal_stmt_value_ref = ref (fun a b -> failwith "not initialized")
let equal_value a b =
match !busy_with_equal with
| Not_busy -> assert false
| Structural_equal -> !equal_stmt_value_ref a b
| Referential_equal -> true This is due to generated code being of the form: let rec equal_stmt =
let _0 () = ... in
fun a b -> ... When one needs to depend on one of the generated functions in the same let equal_value equal_stmt_value a b =
match !busy_with_equal with
| Not_busy -> assert false
| Structural_equal -> equal_stmt_value a b
| Referential_equal -> true and the ppx annotation becomes this: type stmt = {
id : int [@equal equal_id];
value : stmt_value [@equal (equal_value equal_stmt_value)]; (* parens for clarity only *)
} |
We have a large AST definition made of many node types and we'd like to derive two different sets of equality functions:
Our code looks like this:
We want one set of functions with the
equal_
prefix and another set with theequal2_
prefix (or better, a custom name).Is there currently a way to do such thing? Any suggestion on how to make this work?
The text was updated successfully, but these errors were encountered: