No se puede implementar una interfaz en F# con una expresión de objeto cuando el parámetro del método es unit.
No puedo encontrar una forma de implementar una interfaz con una expresión de objeto cuando contiene un método sin tipos que pueda referirse al tipo para el cual se está llevando a cabo la implementación. Un método con firma unit -> string
es un ejemplo simple. Código de ejemplo a continuación:
“`
type AsString =
abstract member asString: unit -> string
type AsString2<‘T> =
abstract member asString: ‘T -> string
type SomeDu =
| A of int
| B of string
| C of float
interface AsString
with member self.asString () =
match self with
| A a -> string a
| B b -> b
| C c -> string c
interface AsString2
with member self.asString x =
if not (x = self) then failwith “el argumento debe ser el contenedor de miembros”
match self with
| A a -> string a
| B b -> b
| C c -> string c
//esta expresión se esperaba que tuviera el tipo AsString pero aquí tiene el tipo SomeDU
let implSomeDU =
{new AsString with
member self.asString () =
match self with
| A a -> string a
| B b -> b
| C c -> string c}
Si intento referirme al tipo de implementación como lo hice con AsString2
, entonces no hay problema con las expresiones de objeto, pero la implementación en DU ahora tiene un requisito que no puedo expresar en el sistema de tipos: el argumento debe ser la instancia de DU o el método no tiene valor.
¿Hay algún truco que me permita implementar AsString
como una expresión de objeto para SomeDu?
davy.ai
Desafortunadamente, no es posible implementar la interfaz
AsString
como una expresión de objeto paraSomeDu
sin modificar la interfaz para incluir un parámetro de tipo que pueda hacer referencia al tipo de implementación. Esto se debe a que el métodoasString
requiere acceso a los casos de unión discriminante, que no se pueden acceder sin conocer el tipo específico de la DU.Una posible solución alternativa es agregar una restricción de tipo al método
asString
, lo que asegura que solo se llame con un argumento que coincida con la instancia DU. Esto se puede lograr agregando un constructor privado aSomeDu
que tome un parámetro del tipo DU y luego comprobando que el argumento coincida con este constructor en el métodoasString
:En este ejemplo agregamos un constructor privado que toma una instancia
SomeDu
como parámetro y no hace nada con ella. Este constructor nos permite hacer referencia al tipoSomeDu
en el métodoasString
, el cual utilizaremos para emparejar el caso DU específico y devolver la representación de cadena correspondiente.Para crear una instancia
SomeDu
, usamos un miembro estáticoCreate
que toma una instanciaSomeDu
y devuelve una nueva instanciaSomeDu
con el constructor privado. Esto nos permite imponer las restricciones de tipo en el métodoasString
, ya que podemos garantizar que el argumento es una instancia válida deSomeDu
.En general, aunque esta solución alternativa agrega algún código adicional, nos permite implementar la interfaz
AsString
para el tipoSomeDu
sin tener que modificar la interfaz o usar restricciones de tipo más complejas.