es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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.

Tags:  , ,

Answer

  1. Avatar for 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 fantasma t, que realmente solo tiene un valor posible Privado: B t. La función make devuelve un valor de ese tipo si el valor predeterminado esperado es realmente B y genera un error de lo contrario.

    Ahora, en las otras partes del código fuera de Lib, podemos usar Check_default para hacer la afirmación en tiempo de compilación. Por ejemplo:

    Esto solo se compilará si el valor predeterminado esperado en Lib es B. Si es cualquier otra cosa, la función make generará un error.

    Por último, observe que Check_default es un functor, lo que significa que podemos usarlo con cualquier otro módulo Lib 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 de Lib.

Comments are closed.