Las uniones discriminadas son una característica poderosa y flexible de F# que permite definir tipos que pueden representar uno de varios casos posibles. Son similares a las enumeraciones en otros lenguajes, pero mucho más expresivas y útiles para modelar datos complejos.

Conceptos Clave

  1. Definición de Uniones Discriminadas: Cómo declarar un tipo de unión discriminada.
  2. Casos de Unión: Diferentes formas en que se pueden definir los casos de una unión discriminada.
  3. Coincidencia de Patrones: Uso de la coincidencia de patrones para trabajar con uniones discriminadas.
  4. Ejemplos Prácticos: Ejemplos de uso en situaciones del mundo real.

Definición de Uniones Discriminadas

En F#, una unión discriminada se define utilizando la palabra clave type seguida del nombre del tipo y los diferentes casos que puede tomar.

type Shape =
    | Circle of float
    | Rectangle of float * float
    | Triangle of float * float * float

En este ejemplo, Shape es una unión discriminada que puede ser un Circle con un radio (float), un Rectangle con ancho y alto (float * float), o un Triangle con tres lados (float * float * float).

Casos de Unión

Cada caso de una unión discriminada puede tener diferentes tipos de datos asociados. Aquí hay algunos ejemplos adicionales:

type Result<'T> =
    | Success of 'T
    | Error of string

type Option<'T> =
    | Some of 'T
    | None

En estos ejemplos, Result<'T> puede ser un Success con un valor de tipo 'T o un Error con un mensaje de error (string). Option<'T> puede ser Some con un valor de tipo 'T o None.

Coincidencia de Patrones

La coincidencia de patrones es una técnica poderosa para trabajar con uniones discriminadas. Permite descomponer y procesar los diferentes casos de una unión discriminada de manera clara y concisa.

let describeShape shape =
    match shape with
    | Circle radius -> sprintf "Circle with radius %f" radius
    | Rectangle (width, height) -> sprintf "Rectangle with width %f and height %f" width height
    | Triangle (a, b, c) -> sprintf "Triangle with sides %f, %f, %f" a b c

En este ejemplo, la función describeShape toma un Shape y utiliza la coincidencia de patrones para devolver una descripción del mismo.

Ejemplos Prácticos

Ejemplo 1: Modelado de Resultados de Operaciones

type OperationResult =
    | Success of string
    | Failure of string

let performOperation x y =
    if y = 0 then
        Failure "Division by zero"
    else
        Success (sprintf "Result is %f" (float x / float y))

let result = performOperation 10 0

match result with
| Success message -> printfn "Operation succeeded: %s" message
| Failure error -> printfn "Operation failed: %s" error

Ejemplo 2: Manejo de Opciones

type Option<'T> =
    | Some of 'T
    | None

let findElement list element =
    if List.contains element list then
        Some element
    else
        None

let result = findElement [1; 2; 3] 2

match result with
| Some value -> printfn "Element found: %d" value
| None -> printfn "Element not found"

Ejercicio Práctico

Ejercicio 1: Modelar un Sistema de Tickets

Define una unión discriminada Ticket que pueda representar tres tipos de tickets: Bug, FeatureRequest y Support. Cada tipo de ticket debe tener diferentes datos asociados.

type Ticket =
    | Bug of string * int
    | FeatureRequest of string * string
    | Support of string

let describeTicket ticket =
    match ticket with
    | Bug (description, severity) -> sprintf "Bug: %s (Severity: %d)" description severity
    | FeatureRequest (description, requester) -> sprintf "Feature Request: %s (Requested by: %s)" description requester
    | Support description -> sprintf "Support: %s" description

// Prueba tu función con diferentes tipos de tickets
let ticket1 = Bug ("Null pointer exception", 1)
let ticket2 = FeatureRequest ("Add dark mode", "Alice")
let ticket3 = Support "Cannot login"

printfn "%s" (describeTicket ticket1)
printfn "%s" (describeTicket ticket2)
printfn "%s" (describeTicket ticket3)

Solución

type Ticket =
    | Bug of string * int
    | FeatureRequest of string * string
    | Support of string

let describeTicket ticket =
    match ticket with
    | Bug (description, severity) -> sprintf "Bug: %s (Severity: %d)" description severity
    | FeatureRequest (description, requester) -> sprintf "Feature Request: %s (Requested by: %s)" description requester
    | Support description -> sprintf "Support: %s" description

// Prueba tu función con diferentes tipos de tickets
let ticket1 = Bug ("Null pointer exception", 1)
let ticket2 = FeatureRequest ("Add dark mode", "Alice")
let ticket3 = Support "Cannot login"

printfn "%s" (describeTicket ticket1)
printfn "%s" (describeTicket ticket2)
printfn "%s" (describeTicket ticket3)

Conclusión

Las uniones discriminadas son una herramienta poderosa en F# para modelar datos que pueden tener múltiples formas. Combinadas con la coincidencia de patrones, permiten escribir código claro y conciso para manejar diferentes casos de datos. En el próximo módulo, exploraremos cómo las uniones discriminadas se integran con otras características de F# para crear programas robustos y expresivos.

Curso de Programación en F#

Módulo 1: Introducción a F#

Módulo 2: Conceptos Básicos

Módulo 3: Programación Funcional

Módulo 4: Estructuras de Datos Avanzadas

Módulo 5: Programación Orientada a Objetos en F#

Módulo 6: Programación Asíncrona y Paralela

Módulo 7: Acceso y Manipulación de Datos

Módulo 8: Pruebas y Depuración

Módulo 9: Temas Avanzados

Módulo 10: Aplicaciones Prácticas

© Copyright 2024. Todos los derechos reservados