Habilidad para provocar errores de compilación al cambiar el valor en OCaml.
Me gustaría expresar, de manera compilada, que mi código funciona bajo la suposición de que un valor es una cierta constante. Para simplificar, digamos que tengo este módulo:
module Lib : sig
type t = A|B|C|D
val default : t
val f : t option -> unit
end = struct
type t = A|B|C|D
let default = B
let f _ = ()
end
Y escribo código fuera de Lib
y quiero afirmar de manera compilada que necesito que el valor predeterminado sea B
. Esto significa que quiero un error de compilación cuando Lib.default
es diferente de B
, en cuyo caso quiero revisar si mi código está bien con el valor diferente. De esta manera, no tendría que leer las notas de lanzamiento de la biblioteca, el compilador me llamaría de vuelta.
Tengo cierto control sobre Lib
, por lo que puedo cambiarlo si es necesario. Estoy interesado en otras formas de estructurarlo si esto hace que la afirmación en tiempo de compilación sea más fácil, por no decir posible.
Tengo otras partes del código que no dependen de esto, por ejemplo:
let config : Lib.t option =
match Lib.default with
| A
| B
| C -> None
| D -> Some C
Estaba pensando en hacer subtipos, como en
type t = [`A|`B|`C|`D]
val default : [`B]
pero entonces pierdo la información de que default
puede cambiar a otros constructores de t
, y luego esto daría un error de compilación diciendo que hacer coincidir con A
es imposible.
let config : Lib.t option =
match Lib.default with
| `A
| `B
| `C -> None
| `D -> Some `C
Gracias.
davy.ai
Un enfoque para lograr esta aserción en tiempo de compilación sería utilizar un tipo fantasma. Podemos introducir un nuevo módulo en
Lib
específicamente para este propósito, que expone un tipo que lleva información sobre el valor predeterminado esperado. Esto es lo que podría parecer:La función
Chek_default
toma un argumento de módulo que especifica el valor predeterminado esperado y devuelve un módulo que expone un tipo fantasmat
, que realmente solo tiene un valor posiblePrivado: B t
. La funciónmake
devuelve un valor de ese tipo si el valor predeterminado esperado es realmenteB
y genera un error de lo contrario.Ahora, en las otras partes del código fuera de
Lib
, podemos usarCheck_default
para hacer la afirmación en tiempo de compilación. Por ejemplo:Esto solo se compilará si el valor predeterminado esperado en
Lib
esB
. Si es cualquier otra cosa, la funciónmake
generará un error.Por último, observe que
Check_default
es un functor, lo que significa que podemos usarlo con cualquier otro móduloLib
que definamos en el futuro, simplemente pasando el módulo al functor. De esta manera, la aserción en tiempo de compilación permanece en su lugar en diferentes versiones deLib
.