You can try to use first class modules. This allows you to conveniently use modules and all the datatypes you may want to define them.
Here’s something to get you started:
type game_state
type foe_bullet
module Foe : sig
(** The type for foe implementations. *)
module type T = sig
type t
val gun : t -> game_state -> int -> t * foe_bullet list
end
type t
val make : (module T with type t = 'a) -> 'a -> t
val gun : t -> game_state -> int -> t * foe_bullet list
end = struct
module type T = sig
type t
val gun : t -> game_state -> int -> t * foe_bullet list
end
type t = V : (module T with type t = 'a) * 'a -> t
let make m foe = V (m, foe)
let gun (V ((module F) as m, foe)) st i =
let foe', bullets = F.gun foe st i in
make m foe', bullets
end