operadores - reales en haskell
¿Debo usar clases de tipo o no? (2)
Tengo algunas dificultades para entender cuándo y cuándo no utilizar typeclass en mi código. Me refiero a crear los míos , y no usar clases de tipos ya definidas , por supuesto. Por ejemplo (ejemplo muy estúpido), debería hacerlo:
data Cars = Brakes | Wheels | Engine
data Computers = Processor | RAM | HardDrive
class Repairable a where
is_reparaible :: a -> Bool
instance Repairable Cars where
is_repairable (Brakes) = True
is_repairable (Wheels) = False
is_repairable (Engine) = False
instance Repairable Computers where
is_repairable (Processor) = False
is_repairable (RAM) = False
is_repairable (HardDrive) = True
checkState :: (Reparaible a) => a -> ...
checkState a = ...
(Obviamente, este es un ejemplo estúpido e incompleto).
Pero esto es mucho para un pequeño uso, ¿no? Por qué no debería hacer algo simple y solo definir funciones sin definir nuevos tipos de datos y clases de tipos (con sus instancias).
Este ejemplo es demasiado simple, pero en los hechos, a menudo veo algo así (nuevos tipos de datos + clases de tipo + instancias) cuando navego por el código de Haskell en github en lugar de solo definir funciones.
Entonces, ¿cuándo debería crear nuevos tipos de datos, tipos de clases, etc. y cuándo debería usar funciones?
Gracias.
Por qué no debería hacer algo simple y solo definir funciones sin definir nuevos tipos de datos y clases de tipos (con sus instancias).
¿Por qué de hecho? Podrías simplemente definir:
checkState :: (a -> Bool) -> (a -> b) -> (a -> b) -> a -> b
checkState is_repairable repairs destroy a
= if (is_repairable a) then repairs a else destroy a
Las personas hacen mal uso de las clases de tipo todo el tiempo. No significa que sea idiomático.
Para responder a su pregunta más general, aquí hay algunas reglas prácticas para cuándo usar clases de tipo y cuándo no usarlas:
Use clases de tipo si:
Solo hay un comportamiento correcto por tipo dado
La clase de tipo tiene ecuaciones asociadas (es decir, "leyes") que todas las instancias deben satisfacer
No use clases de tipo si:
Estás tratando de simplemente nombrar las cosas. Para eso están los módulos y los espacios de nombres.
Una persona que utiliza su clase de tipo no puede razonar sobre cómo se comportará sin mirar el código fuente de las instancias
Encuentra que las extensiones que tiene que encender están fuera de control
A menudo puede usar un tipo de datos en lugar de una clase de tipo, por ejemplo
data Repairable a = Repairable
{ getRepairable :: a
, isRepairable :: Bool
, canBeRepairedWith :: [Tool] -> Bool -- just to give an example of a function
}
Por supuesto, debe pasar este valor de forma explícita, pero esto puede ser algo bueno si tiene múltiples opciones (por ejemplo, piense en la Sum
y el Product
como posibles Monoid
para los números). Excepto que tienes más o menos la misma expresividad que para una clase de tipo.