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.

F# – ¿Cuál es la forma más limpia de extraer/desenvolver el valor tipado de un caso esperado dentro de una Unión Discriminada?

La estructura general de tipos y su uso en mi actual código F# funcionan muy bien. Sin embargo, deseo obtener perspectiva si estoy haciendo algo incorrectamente o siguiendo algún tipo de anti-patrón. Me encuentro a menudo esperando esencialmente un tipo particular en una lógica particular que está tomando de un tipo más general que es una Unión Discriminada unificando un montón de tipos distintos que siguen todas capas de procesamiento común.

Básicamente, necesito versiones particulares de esta función:

‘GeneralDiscriminatedUnionType -> ‘SpecificCaseType

Me encuentro repitiendo muchas declaraciones como la siguiente:

let checkPromptUpdated (PromptUpdated prompt) = prompt

Esta es la forma más simple que he encontrado para hacer esto; sin embargo, todas estas tienen una advertencia de compilador válida que tiene sentido que podría haber un problema si la función es llamada con un tipo diferente al esperado. Esto es justo, pero hasta ahora tengo como 40 a 50 de estas.

Así que empecé a intentar lo siguiente, que es en realidad mejor, porque si se utiliza incorrectamente, levantaría una excepción válida (ambas son lo mismo):

let checkPromptUpdated input = match input with | PromptUpdated prompt -> prompt | _ -> invalidOp “Esperando Prompt”
let checkPromptUpdated = function | PromptUpdated prompt -> prompt | _ -> invalidOp “Esperando Prompt”

Sin embargo, esto se ve mucho más desordenado y estoy tratando de encontrar si alguien tiene alguna sugerencia antes de hacer este desorden todo el tiempo.

¿Hay alguna manera de aplicar esta lógica más amplia a una función más general que luego me permitiría escribir esto 50 a 100 veces de manera más limpia, directa y legible?

Esta pregunta es solo para intentar escribir un código más limpio.

Este es un ejemplo de una DU para la que estoy tratando de escribir funciones para poder extraer los valores tipados particulares de los casos:

type StateEvent =
| PromptUpdated of Prompt
| CorrectAnswerUpdated of CorrectAnswer
| DifficultyUpdated of Difficulty
| TagsUpdated of Tag list
| NotesUpdated of Notes
| AuthorUpdated of Author

Tags:  ,

Answer

  1. Avatar for davy.ai

    El problema en cuestión es que el usuario se encuentra frecuentemente necesitando extraer un tipo de caso específico de una Unión Discriminada (DU) que unifica múltiples tipos. El usuario ha encontrado dos formas de hacer esto: bien haciendo coincidir el patrón directamente con el caso específico, o bien usando una coincidencia general y lanzando una excepción con un uso incorrecto.

    Aunque lo segundo proporciona una solución más robusta, el usuario está tratando de encontrar una forma de escribir un código más limpio y directo sin repetir la misma declaración varias veces.

    Una solución potencial a este problema podría ser crear una función genérica que tome la DU y el tipo de caso específico como argumentos y devuelva el caso específico si existe en la DU. Esto permitiría al usuario escribir la función sólo una vez y reutilizarla para todos los tipos de casos específicos que necesiten extraer.

    Aquí hay una implementación de ejemplo de tal función:

    let extractSpecificCase<'a> (du: StateEvent) : option<'a> =
        match du with
        | :? 'a as specificCase -> Some specificCase
        | _ -> None
    

    La función toma la DU StateEvent y un tipo genérico 'a que representa el tipo de caso específico. Hace coincidir el patrón en la DU utilizando un patrón de prueba de tipo (:?) y comprueba si el tipo coincide con el tipo genérico 'a. Si es así, devuelve Some specificCase. Si no, devuelve None.

    El usuario puede utilizar esta función para extraer los tipos de casos específicos que necesitan de la siguiente manera:

    let prompt = extractSpecificCase<prompt> stateEvent
    let correctAnswer = extractSpecificCase<correctanswer> stateEvent
    let difficulty = extractSpecificCase<difficulty> stateEvent
    let tags = extractSpecificCase<tag list=""> stateEvent
    let notes = extractSpecificCase<notes> stateEvent
    let author = extractSpecificCase<author> stateEvent
    

    De esta manera, sólo necesitan llamar a la función una vez para cada tipo de caso específico, haciendo que el código sea más limpio y legible.

    En general, la estructura y la utilización del tipo del usuario parecen estar funcionando bien. Al crear una función genérica para manejar la extracción de tipos de casos específicos de su DU, pueden mejorar aún más la limpieza y la legibilidad de su código.

Comments are closed.