Following up the question “Derived enums as bitmap masks” I have a lot of bitmask types and the need to decode them. So for example I have this code:
open Core
open Sexplib0.Sexp_conv
module Bitmask = struct
let mask_list l f =
l |> List.map ~f:(fun el -> (el, f el))
let mask_decode x masks =
List.fold_left ~f:(fun acc (f, mask) ->
if x land mask <> 0 then f::acc else acc
) ~init:[] masks
end
type bm1 =
| FEATURE1 [@value 0x20]
| FEATURE2 [@value 0x80]
[@@deriving enum, enumerate, sexp, show {with_path = false}]
type bm1_mask = bm1 list
[@@deriving show, sexp]
let bm1_masks =
Bitmask.mask_list all_of_bm1 bm1_to_enum
let decode_bm1 x =
Bitmask.mask_decode x bm1_masks
type bm2 =
| FEATURE1 [@value 0x20]
| FEATURE2 [@value 0x80]
[@@deriving enum, enumerate, sexp, show {with_path = false}]
type bm2_mask = bm2 list
[@@deriving show, sexp]
let bm2_masks =
Bitmask.mask_list all_of_bm2 bm2_to_enum
let decode_bm2 x =
Bitmask.mask_decode x bm2_masks
And many, many pages of these bm* bitmask feature types to decode. So obvious thought is to functorize, or fold any other way this code. But the problem here is the derivers. Is it possible somehow to put this deriving code into the Functor/Monad/whatever fits? Or any other strategy to handle this?
I don’t think that derivers prevent functorization: the functor could just suppose that the type given in the module parameter comes with the functions produced by the derivers.
module type ENUM = sig
type t
[@@deriving enum, enumerate, sexp, show {with_path = false}]
end
module Make_bitmask (Enum : ENUM) = struct
include Enum
type mask = t list
[@@deriving show, sexp]
let masks = Bitmask.mask_list all Enum.to_enum
let decode x =
Bitmask.mask_decode x masks
end
Then you can define Bm1.t and Bm2.t just by instantiating this functor.
module Bm1 = Make_bitmask (struct
type t =
| FEATURE1 [@value 0x20]
| FEATURE2 [@value 0x80]
[@@deriving enum, enumerate, sexp, show {with_path = false}]
end)
module Bm2 = Make_bitmask (struct
type t =
| FEATURE1 [@value 0x20]
| FEATURE2 [@value 0x80]
[@@deriving enum, enumerate, sexp, show {with_path = false}]
end)
Oops! Here is a fix to my previous proposal. Unfortunately, it is a bit more verbose…
module type ENUM = sig
type t
[@@deriving enum, enumerate, sexp, show {with_path = false}]
end
module Make_bitmask (Enum : ENUM) = struct
open Enum
type mask = t list
[@@deriving show, sexp]
let masks = Bitmask.mask_list all Enum.to_enum
let decode x =
Bitmask.mask_decode x masks
end
module Bm1 = struct
module Enum = struct
type t =
| FEATURE1 [@value 0x20]
| FEATURE2 [@value 0x80]
[@@deriving enum, enumerate, sexp, show {with_path = false}]
end
include Enum
include Make_bitmask (Enum)
end
module Bm2 = struct
module Enum = struct
type t =
| FEATURE1 [@value 0x20]
| FEATURE2 [@value 0x80]
[@@deriving enum, enumerate, sexp, show {with_path = false}]
end
include Enum
include Make_bitmask (Enum)
end
let x = Bm1.FEATURE1