Generalize the fields of a record to apply validation (& other ops)

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.

10 Likes