haskell ocaml

Or-patrones en Haskell



ocaml (3)

En OCaml, estaba acostumbrado a escribir código que parecía:

let combine o1 o2 = match o1, o2 with | Valid, Invalid | Invalid, Valid -> Invalid | _ -> ...

No encontré una forma de escribir o-patrones en Haskell y realmente lo extraño. ¿Alguien tiene una solución?


Hay una proposal para agregar o-patrones a GHC.

Hasta entonces (además de los otros ejemplos), pueden emplearse sinónimos de patrón para medios similares:

data ABC = A Int | B Int | C Bool ab :: ABC -> Maybe Int ab (A i) = Just i ab (B i) = Just i ab C{} = Nothing pattern AB :: Int -> ABC pattern AB i <- (ab -> Just i)

Si desea hacer coincidir valores de tipos separados (como Int y Bool ), puede crear algún tipo existencial restringido

data Showable where Showable :: Show a => a -> Showable ac :: ABC -> Maybe Showable ac (A i) = Just (Showable i) ac (C b) = Just (Showable b) ac B{} = Nothing pattern AC :: () => Show a => a -> ABC pattern AC showable <- (ac -> Just (Showable showable)) showAC :: ABC -> String showAC (AC showable) = "A or C: " ++ show showable showAC (B i) = "B: " ++ show i


No creo que esto sea posible en haskell. Sin embargo, hay algunas alternativas:

Factoriza el código común con un enlace where

Esto no tiene mucho sentido en su ejemplo, pero es útil si tiene más código en el cuerpo de la expresión del caso:

combine o1 o2 = case (o1,o2) of (Valid, Invalid) -> handleInvalid (Invalid, Valid) -> handleInvalid ... where handleInvalid = ...

Usa patrones comodín

En mi experiencia, no sucede tan a menudo que desee utilizar dos o patrones en una coincidencia de patrón. En este caso, puede manejar todos los casos "buenos" y usar un patrón de comodín para el resto:

combine o1 o2 = case (o1,o2) of (Valid, Valid) -> Valid -- This is the only valid case _ -> Invalid -- All other cases are invalid

Esto tiene la desventaja de que pasa por alto el verificador de exhaustividad y que no puede usar patrones comodín para otros propósitos.

Usa guardias y ==

Si los tipos con los que desea hacer coincidencias son similares a una enumeración, podría considerar crear una instancia de Eq . Entonces puedes usar == y || para hacer coincidir varios constructores en una guardia:

combine o1 o2 | o1 == Invalid && o2 == Valid || o1 == Valid && o2 == Invalid = Invalid | ...

Estoy de acuerdo en que esto no se ve tan bien y también tiene la desventaja de pasar por alto el comprobador de exhaustividad y no le advierte si los patrones se superponen, así que no lo recomendaría.