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.

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?

Tags:  

Answer

  1. Avatar for davy.ai

    Desafortunadamente, no es posible implementar la interfaz AsString como una expresión de objeto para SomeDu 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étodo asString 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 a SomeDu que tome un parámetro del tipo DU y luego comprobando que el argumento coincida con este constructor en el método asString:

    type AsString =
        abstract member asString: unit -> string
    
    type SomeDu =
        | A of int
        | B of string
        | C of float
        interface AsString
            with member self.asString () =
                    let du =
                        match box self with
                        | :? A as a -> a :> SomeDu
                        | :? B as b -> b :> SomeDu
                        | :? C as c -> c :> SomeDu
                        | _ -> failwith "invalid someDu instance"
                    match du with
                    | A a -> string a
                    | B b -> b
                    | C c -> string c
        private SomeDu(someDu: SomeDu) = ()
        static member Create(someDu: SomeDu) = SomeDu(someDu)
    
    // implementar como interfaz AsString sin expresión de objeto
    let someDu = SomeDu.Create(A 42)
    let asStringImpl = someDu :> AsString
    let asStringResult = asStringImpl.asString() // devuelve "42"
    

    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 tipo SomeDu en el método asString, 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ático Create que toma una instancia SomeDu y devuelve una nueva instancia SomeDu con el constructor privado. Esto nos permite imponer las restricciones de tipo en el método asString, ya que podemos garantizar que el argumento es una instancia válida de SomeDu.

    En general, aunque esta solución alternativa agrega algún código adicional, nos permite implementar la interfaz AsString para el tipo SomeDu sin tener que modificar la interfaz o usar restricciones de tipo más complejas.

Comments are closed.