Esto es algo así como una pregunta filosófica, pero espero haber sido respondida por documentación oficial o "palabra de dios" (léase: SPJ). ¿Hay alguna razón específica por la cual el comité Haskell eligió requerir interfaces explícitas en forma de clases de tipos en lugar de una solución más uniforme basada en la coincidencia de patrones?¿Por qué tipo de clases en lugar de simplemente coincidencia de patrones?
A modo de ejemplo, tomar Eq
:
class Eq a where
(==), (/=) :: a -> a -> Bool
x == y = not $ x /= y
x /= y = not $ x == y
instance Eq Int where
(==) = internalIntEq
qué nosotros no pudimos hacer algo como esto en su lugar (oso con el pseudo-Haskell):
(==), (/=) :: a -> a -> Bool
default x == y = not $ x /= y -- 1
default x /= y = not $ x == y
(Int a) == (Int b) = a `internalIntEq` b -- 2
Es decir, si Haskell fueron a permitir la coincidencia de patrones de los tipos de datos ordinarios, entonces:
Los programadores podrían crear clases ad-hoc, es decir,
instance
serían implícita (2)Tipos todavía podía inferirse y emparejados estáticamente (
SupportsEqualsEquals a => ...
)implementaciones predeterminadas vendría “gratis”
Clases podría fácilmente extenderse sin romper nada
Tendría que haber una manera de especificar un patrón predeterminado (1) que, aunque declarado antes de otro s, siempre coincide con el último. ¿Alguna de estas características hipotéticas choca con algo inherente a Haskell? ¿Sería difícil o imposible inferir correctamente los tipos? Parece ser una característica poderosa que se combinaría muy bien con el resto de Haskell, así que creo que hay una buena razón por la que no lo hacemos así. ¿Es este mecanismo de polimorfismo ad-hoc simplemente también ad-hoc?
No soy muy versado en esto, pero creo que uno de los principales problemas es que pierdes parametricidad y, por lo tanto, teoremas libres: sabes qué 'id :: a -> a' o' fst :: (a, b) -> a' hacen simplemente por sus firmas de tipo, porque solo tienen polimorfismo paramétrico. Si tiene algún tipo de mecanismo de tipo de letra, entonces pierde la parametricidad. Por ejemplo, 'a -> a -> Bool' admite solo dos implementaciones (totales) en Haskell (' const $ const True' y 'const $ const False'); si tiene typecase, entonces pierde esta garantía. –
@ AntalS-Z: Solo me aseguro de que te entiendo correctamente. ¿Estás diciendo que puedo declarar 'id :: a -> a', luego definir' id (Int i) = i + 1'? Porque ese no es el caso: la última definición sería del tipo 'SupportsPlus a => a -> a', que es incompatible. –
Eso es lo que parece de su pregunta; su firma de tipo para '(==)' se da como 'a -> a -> Bool'. Si tiene que especificar una "clase de tipo" 'SupportsEquals', entonces parece que todo lo que ha hecho es sintaxis comercializada --- no veo por qué es * diferente *. Y no creo que pueda expresar clases de tipos de parámetros múltiples, dependencias funcionales o tipos asociados, aunque estos ciertamente no estaban en el plan original. De hecho, ¿puede incluso expresar clases de tipo de mayor nivel? ¿Cómo sabrías que 'return :: a -> m a' debería ser ad-hoc sobre' m', y no 'a'? –