Finally, I’ve some time.
Here a possible solution to your problem. I’m using modules and first-class modules to hold the meta informations on fields because I prefer this syntactic construction, but conceptually this is the same thing that you did with simple records.
(* the module type for operators on fields *)
module type Meta = sig
type t
val id : int
val validate : t -> bool
val size : t -> int
end
(* a meta field is a value of some type 'a with operations over it *)
type 'a meta_field = 'a * (module Meta with type t = 'a)
(* a field is a meta_field on some type 'a *)
type field = F : 'a meta_field -> field
(* we can check if a field is valid *)
let valid_field (F (v, (module M))) = M.validate v
(* we can compute the size of a field *)
let field_size (F (v, (module M))) = M.size v
(* the type of a person with meta fields *)
type person = {
name : string meta_field;
surname : string meta_field;
age : int meta_field;
}
(* the function you wanted to compute : the list of fields of a person record *)
let fields_list {name; surname; age} = [F name; F surname; F age]
(* We can now use it to check if a person is valid and compute its size *)
let valid person = List.for_all valid_field (fields_list person)
let size person =
fields_list person
|> List.map field_size
|> List.fold_left (+) 0
(* the different modules of operators for the distinct fields *)
module Name_meta = struct
type t = string
let id = 1
let validate _ = true
let size = String.length
end
module Surname_meta = struct
type t = string
let id = 2
let validate s = String.contains s 'f'
let size = String.length
end
module Age_meta = struct
type t = int
let id = 3
let validate i = i > 25
let size i = i
end
(* and an example *)
let batman = {
name = ("Bruce", (module Name_meta));
surname = ("Wayne", (module Surname_meta));
age = (34, (module Age_meta))
}
(* use of the previous functions *)
valid batman;;
- : bool = false
size batman;;
- : int = 44
Hope this is what you’re searching for. If you have some questions, don’t hesitate to ask.